    001/*
    002 * Copyright (c) 2007-2016 Concurrent, 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( "Concurrent, Inc - %s %s", CASCADING, getReleaseFull() );
    094    else
    095      releaseVersion = String.format( "Concurrent, Inc - %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  }