001/*
002 * Copyright (c) 2007-2017 Xplenty, Inc. All Rights Reserved.
003 *
004 * Project and contact information: http://www.cascading.org/
005 *
006 * This file is part of the Cascading project.
007 *
008 * Licensed under the Apache License, Version 2.0 (the "License");
009 * you may not use this file except in compliance with the License.
010 * You may obtain a copy of the License at
011 *
012 *     http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing, software
015 * distributed under the License is distributed on an "AS IS" BASIS,
016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 * See the License for the specific language governing permissions and
018 * limitations under the License.
019 */
020
021package cascading.util;
022
023import java.io.IOException;
024import java.io.InputStream;
025import java.net.URL;
026import java.util.Collections;
027import java.util.List;
028import java.util.Properties;
029import java.util.Set;
030
031import org.slf4j.Logger;
032import org.slf4j.LoggerFactory;
033
034/**
035 *
036 */
037public class Version
038  {
039  private static final Logger LOG = LoggerFactory.getLogger( Version.class );
040
041  private static boolean printedVersion = false;
042
043  public static final String CASCADING_RELEASE_MAJOR = "cascading.release.major";
044  public static final String CASCADING_RELEASE_MINOR = "cascading.release.minor";
045  public static final String CASCADING_BUILD_NUMBER = "cascading.build.number";
046  public static final String CASCADING = "Cascading";
047
048  public static Properties versionProperties;
049
050  private static synchronized Properties getVersionProperties()
051    {
052    try
053      {
054      if( versionProperties == null )
055        {
056        versionProperties = loadVersionProperties();
057
058        if( versionProperties.isEmpty() )
059          LOG.warn( "unable to load version information" );
060        }
061      }
062    catch( IOException exception )
063      {
064      LOG.warn( "unable to load version information", exception );
065      versionProperties = new Properties();
066      }
067
068    return versionProperties;
069    }
070
071  public static synchronized void printBanner()
072    {
073    // only print once
074    if( printedVersion )
075      return;
076
077    printedVersion = true;
078
079    String version = getVersionString();
080
081    if( version != null )
082      LOG.info( version );
083    }
084
085  public static String getVersionString()
086    {
087    if( getVersionProperties().isEmpty() )
088      return null;
089
090    String releaseVersion;
091
092    if( getReleaseBuild() == null || getReleaseBuild().isEmpty() )
093      releaseVersion = String.format( "%s %s", CASCADING, getReleaseFull() );
094    else
095      releaseVersion = String.format( "%s %s-%s", CASCADING, getReleaseFull(), getReleaseBuild() );
096
097    return releaseVersion;
098    }
099
100  public static String getRelease()
101    {
102    if( getVersionProperties().isEmpty() )
103      return null;
104
105    if( getReleaseBuild() == null || getReleaseBuild().isEmpty() )
106      return String.format( "%s", getReleaseFull() );
107    else
108      return String.format( "%s-%s", getReleaseFull(), getReleaseBuild() );
109    }
110
111  public static String getReleaseFull()
112    {
113    String releaseFull;
114
115    if( getReleaseMinor() == null || getReleaseMinor().isEmpty() )
116      releaseFull = getReleaseMajor();
117    else
118      releaseFull = String.format( "%s.%s", getReleaseMajor(), getReleaseMinor() );
119
120    return releaseFull;
121    }
122
123  public static boolean hasMajorMinorVersionInfo()
124    {
125    return !Util.isEmpty( getReleaseMinor() ) && !Util.isEmpty( getReleaseMajor() );
126    }
127
128  public static boolean hasAllVersionInfo()
129    {
130    return !Util.isEmpty( getReleaseBuild() ) && hasMajorMinorVersionInfo();
131    }
132
133  public static String getReleaseBuild()
134    {
135    return getVersionProperties().getProperty( CASCADING_BUILD_NUMBER );
136    }
137
138  public static String getReleaseMinor()
139    {
140    return getVersionProperties().getProperty( CASCADING_RELEASE_MINOR );
141    }
142
143  public static String getReleaseMajor()
144    {
145    return getVersionProperties().getProperty( CASCADING_RELEASE_MAJOR );
146    }
147
148  public static Properties loadVersionProperties() throws IOException
149    {
150    Properties properties = new Properties();
151
152    List<URL> resources = Collections.list( Version.class.getClassLoader().getResources( "cascading/version.properties" ) );
153
154    if( resources.isEmpty() )
155      return properties;
156
157    warnOnDuplicate( resources );
158
159    InputStream stream = resources.get( 0 ).openStream();
160
161    if( stream == null )
162      return properties;
163
164    try
165      {
166      properties.load( stream );
167      }
168    finally
169      {
170      stream.close();
171      }
172
173    stream = Version.class.getClassLoader().getResourceAsStream( "cascading/build.number.properties" );
174
175    if( stream != null )
176      {
177      try
178        {
179        properties.load( stream );
180        }
181      finally
182        {
183        stream.close();
184        }
185      }
186
187    return properties;
188    }
189
190  /**
191   * A shaded jar will have multiple version.properties, e.g.
192   * <pre>
193   * file:/mnt/var/lib/hadoop/tmp/hadoop-unjar7817209360894770970/cascading/version.properties
194   * jar:file:/mnt/single-load/./load-hadoop2-tez-20150729.jar!/cascading/version.properties
195   * </pre>
196   * <p/>
197   * only warn if there are duplicates within a protocol, not across since we should only be seeing file: and jar:
198   */
199  private static void warnOnDuplicate( List<URL> resources )
200    {
201    if( resources.size() == 1 )
202      return;
203
204    SetMultiMap<String, String> map = new SetMultiMap<>();
205
206    for( URL resource : resources )
207      map.put( resource.getProtocol(), resource.toString() );
208
209    for( String key : map.getKeys() )
210      {
211      Set<String> values = map.getValues( key );
212
213      if( values.size() > 1 )
214        LOG.warn( "found multiple 'cascading/version.properties' files on the CLASSPATH. Please check your dependencies: {}, using first returned", Util.join( values, "," ) );
215      }
216    }
217  }