001    /*
002     * SonarQube, open source software quality management tool.
003     * Copyright (C) 2008-2014 SonarSource
004     * mailto:contact AT sonarsource DOT com
005     *
006     * SonarQube is free software; you can redistribute it and/or
007     * modify it under the terms of the GNU Lesser General Public
008     * License as published by the Free Software Foundation; either
009     * version 3 of the License, or (at your option) any later version.
010     *
011     * SonarQube is distributed in the hope that it will be useful,
012     * but WITHOUT ANY WARRANTY; without even the implied warranty of
013     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014     * Lesser General Public License for more details.
015     *
016     * You should have received a copy of the GNU Lesser General Public License
017     * along with this program; if not, write to the Free Software Foundation,
018     * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
019     */
020    package org.sonar.api.config;
021    
022    import com.google.common.annotations.VisibleForTesting;
023    import com.google.common.collect.Maps;
024    import org.apache.commons.codec.binary.Base64;
025    import org.apache.commons.io.IOUtils;
026    import org.apache.commons.lang.StringUtils;
027    import org.sonar.api.utils.DateUtils;
028    
029    import javax.annotation.Nullable;
030    
031    import java.io.IOException;
032    import java.io.StringReader;
033    import java.util.Calendar;
034    import java.util.Date;
035    import java.util.List;
036    import java.util.Map;
037    
038    /**
039     * SonarSource license. This class aims to extract metadata but not to validate or - of course -
040     * to generate license
041     *
042     * @since 3.0
043     */
044    public final class License {
045      private String product;
046      private String organization;
047      private String expirationDate;
048      private String type;
049      private String server;
050      private Map<String, String> additionalProperties;
051    
052      private License(Map<String, String> properties) {
053        this.additionalProperties = Maps.newHashMap(properties);
054        product = StringUtils.defaultString(get("Product", properties), get("Plugin", properties));
055        organization = StringUtils.defaultString(get("Organisation", properties), get("Name", properties));
056        expirationDate = StringUtils.defaultString(get("Expiration", properties), get("Expires", properties));
057        type = get("Type", properties);
058        server = get("Server", properties);
059        // SONAR-4340 Don't expose Digest and Obeo properties
060        additionalProperties.remove("Digest");
061        additionalProperties.remove("Obeo");
062      }
063    
064      private String get(String key, Map<String, String> properties) {
065        additionalProperties.remove(key);
066        return properties.get(key);
067      }
068    
069      /**
070       * Get additional properties available on this license (like threshold conditions)
071       * @since 3.6
072       */
073      public Map<String, String> additionalProperties() {
074        return additionalProperties;
075      }
076    
077      @Nullable
078      public String getProduct() {
079        return product;
080      }
081    
082      @Nullable
083      public String getOrganization() {
084        return organization;
085      }
086    
087      @Nullable
088      public String getExpirationDateAsString() {
089        return expirationDate;
090      }
091    
092      @Nullable
093      public Date getExpirationDate() {
094        return DateUtils.parseDateQuietly(expirationDate);
095      }
096    
097      public boolean isExpired() {
098        return isExpired(new Date());
099      }
100    
101      @VisibleForTesting
102      boolean isExpired(Date now) {
103        Date date = getExpirationDate();
104        return date != null && !date.after(org.apache.commons.lang.time.DateUtils.truncate(now, Calendar.DATE));
105      }
106    
107      @Nullable
108      public String getType() {
109        return type;
110      }
111    
112      @Nullable
113      public String getServer() {
114        return server;
115      }
116    
117      public static License readBase64(String base64) {
118        return readPlainText(new String(Base64.decodeBase64(base64.getBytes())));
119      }
120    
121      @VisibleForTesting
122      static License readPlainText(String data) {
123        Map<String, String> props = Maps.newHashMap();
124        StringReader reader = new StringReader(data);
125        try {
126          List<String> lines = IOUtils.readLines(reader);
127          for (String line : lines) {
128            if (StringUtils.isNotBlank(line) && line.indexOf(':') > 0) {
129              String key = StringUtils.substringBefore(line, ":");
130              String value = StringUtils.substringAfter(line, ":");
131              props.put(StringUtils.trimToEmpty(key), StringUtils.trimToEmpty(value));
132            }
133          }
134    
135        } catch (IOException e) {
136          // silently ignore
137    
138        } finally {
139          IOUtils.closeQuietly(reader);
140        }
141        return new License(props);
142      }
143    }