| /* |
| |
| Derby - Class org.apache.derbyTesting.functionTests.tests.upgradeTests.Version |
| |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to You under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| |
| */ |
| package org.apache.derbyTesting.functionTests.tests.upgradeTests; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.HashMap; |
| |
| import org.apache.derby.iapi.services.info.ProductVersionHolder; |
| |
| /** |
| * <p> |
| * A Derby version. |
| * </p> |
| */ |
| public class Version implements Comparable<Version> |
| { |
| /////////////////////////////////////////////////////////////////////////////////// |
| // |
| // CONSTANTS |
| // |
| /////////////////////////////////////////////////////////////////////////////////// |
| |
| private static final int EXPECTED_LEG_COUNT = 4; |
| |
| /////////////////////////////////////////////////////////////////////////////////// |
| // |
| // STATE |
| // |
| /////////////////////////////////////////////////////////////////////////////////// |
| |
| private int[] _legs; |
| private String _key; |
| private String _branchID; |
| |
| // we keep one class loader per version so that we don't have an explosion |
| // of class loaders for redundant versions |
| private static HashMap<String, ClassLoader> _classLoaders = |
| new HashMap<String, ClassLoader>(); |
| |
| /////////////////////////////////////////////////////////////////////////////////// |
| // |
| // CONSTRUCTOR |
| // |
| /////////////////////////////////////////////////////////////////////////////////// |
| |
| /** Construct a version from four legs */ |
| public Version( int major, int minor, int fixpack, int bugversion ) |
| { |
| this( new int[] { major, minor, fixpack, bugversion } ); |
| } |
| |
| /** Construct a version from its legs */ |
| public Version( int[] legs ) |
| { |
| constructorMinion( legs ); |
| } |
| |
| /** Construct from a Derby ProductVersionHolder */ |
| public Version( ProductVersionHolder pvh ) |
| { |
| constructorMinion( getLegs( pvh ) ); |
| } |
| private void constructorMinion( int[] legs ) |
| { |
| if ( legs == null ) { legs = new int[] {}; } |
| int count = legs.length; |
| |
| if ( count != EXPECTED_LEG_COUNT ) |
| { |
| throw new IllegalArgumentException( "Expected " + EXPECTED_LEG_COUNT + " legs but only saw " + count ); |
| } |
| |
| _legs = new int[ count ]; |
| for ( int i = 0; i < count; i++ ) { _legs[ i ] = legs[ i ]; } |
| |
| makeKey(); |
| } |
| private int[] getLegs( ProductVersionHolder pvh ) |
| { |
| int[] result = new int[ EXPECTED_LEG_COUNT ]; |
| int idx = 0; |
| |
| result[ idx++ ] = pvh.getMajorVersion(); |
| result[ idx++ ] = pvh.getMinorVersion(); |
| result[ idx++ ] = pvh.getMaintVersion() / ProductVersionHolder.MAINT_ENCODING; |
| result[ idx++ ] = pvh.getMaintVersion() % ProductVersionHolder.MAINT_ENCODING; |
| |
| return result; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////////// |
| // |
| // PUBLIC BEHAVIOR |
| // |
| /////////////////////////////////////////////////////////////////////////////////// |
| |
| /** |
| * <p> |
| * Pretty-print this version. |
| * </p> |
| */ |
| public String toString() |
| { |
| return _key; |
| } |
| |
| /** |
| * <p> |
| * Pretty-print the branch id, that is, the major + minor legs of the Version. |
| * </p> |
| */ |
| public String getBranchID() |
| { |
| if ( _branchID == null ) |
| { |
| _branchID = Integer.toString(_legs[ 0 ]) + '.' + Integer.toString(_legs[ 1 ]); |
| } |
| |
| return _branchID; |
| } |
| |
| /** |
| * <p> |
| * Get a class loader for this version. |
| * </p> |
| */ |
| public ClassLoader getClassLoader() |
| { |
| ClassLoader retval = (ClassLoader) _classLoaders.get( _key ); |
| if ( retval != null ) { return retval; } |
| |
| addClassLoader( ); |
| |
| return (ClassLoader) _classLoaders.get( _key ); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////////// |
| // |
| // Comparable BEHAVIOR |
| // |
| /////////////////////////////////////////////////////////////////////////////////// |
| |
| public int compareTo( Version other ) |
| { |
| if ( other == null ) { return 1; } |
| |
| for ( int i = 0; i < EXPECTED_LEG_COUNT; i++ ) |
| { |
| int result = this._legs[ i ] - other._legs[ i ]; |
| |
| if ( result != 0 ) { return result; } |
| } |
| |
| return 0; |
| } |
| |
| public boolean equals( Object other ) { |
| return (other instanceof Version) && (compareTo((Version) other) == 0); |
| } |
| public int hashCode() { return toString().hashCode(); } |
| |
| /////////////////////////////////////////////////////////////////////////////////// |
| // |
| // MINIONS |
| // |
| /////////////////////////////////////////////////////////////////////////////////// |
| |
| /** |
| * <p> |
| * Add the class loader for this version if it doesn't already exist. |
| * </p> |
| */ |
| private void addClassLoader( ) |
| { |
| ClassLoader classLoader = UpgradeClassLoader.makeClassLoader( _legs ); |
| |
| _classLoaders.put( _key, classLoader ); |
| } |
| |
| /** |
| * <p> |
| * Make the key for looking up our class loader. |
| * </p> |
| */ |
| private void makeKey() |
| { |
| StringBuffer buffer = new StringBuffer(); |
| int legCount = _legs.length; |
| |
| for ( int i = 0; i < legCount; i++ ) |
| { |
| if ( i > 0 ) { buffer.append( '.' ); } |
| buffer.append( _legs[ i ] ); |
| } |
| |
| _key = buffer.toString(); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////////// |
| // |
| // INNER CLASSES |
| // |
| /////////////////////////////////////////////////////////////////////////////////// |
| |
| /** |
| * <p> |
| * This is a sequence of Versions. It is the caller's responsibility to |
| * determine whether the Versions are in sort order. |
| * </p> |
| */ |
| public static final class Trajectory implements Comparable |
| { |
| private Version[] _versions; |
| |
| /** |
| * <p> |
| * Construct from a list of Versions. |
| * </p> |
| */ |
| public Trajectory( ArrayList<Version> versionList ) |
| { |
| if (versionList == null) { |
| versionList = new ArrayList<Version>(); |
| } |
| |
| Version[] versions = new Version[ versionList.size() ]; |
| versionList.toArray( versions ); |
| |
| constructorMinion( versions ); |
| } |
| |
| /** |
| * <p> |
| * Construct from an array of Versions. |
| * </p> |
| */ |
| public Trajectory( Version[] versions ) |
| { |
| if ( versions == null ) { versions = new Version[ 0 ]; } |
| |
| constructorMinion( versions ); |
| } |
| |
| private void constructorMinion( Version[] versions ) |
| { |
| int count = versions .length; |
| _versions = new Version[ count ]; |
| |
| for ( int i = 0; i < count; i++ ) { _versions[ i ] = versions[ i ]; } |
| } |
| |
| /** |
| * <p> |
| * Sort this Trajectory so that the Versions are arranged in ascending |
| * order. Returns this Trajectory after the sort. |
| * </p> |
| */ |
| public Trajectory sort() |
| { |
| Arrays.sort( _versions ); |
| |
| return this; |
| } |
| |
| public int getVersionCount() { return _versions.length; } |
| public Version getVersion( int idx ) { return _versions[ idx ]; } |
| |
| /** |
| * <p> |
| * Return the ending Version of this Trajectory. |
| * </p> |
| */ |
| public Version getEndingVersion() |
| { |
| return getVersion( getVersionCount() -1 ); |
| } |
| |
| /** |
| * <p> |
| * Return true if this Trajectory starts at the desired Version. |
| * </p> |
| */ |
| public boolean startsAt( Version candidate ) |
| { |
| return ( getVersion( 0 ).equals( candidate ) ); |
| } |
| |
| /** |
| * <p> |
| * Return true if this Trajectory starts at the desired branch. |
| * </p> |
| */ |
| public boolean startsAt( String branchID ) |
| { |
| return ( getVersion( 0 ).getBranchID().equals( branchID ) ); |
| } |
| |
| /** |
| * <p> |
| * Return true if this Trajectory contains the desired Version. |
| * </p> |
| */ |
| public boolean contains( Version candidate ) |
| { |
| int count = getVersionCount(); |
| for ( int i = 0; i < count; i++ ) |
| { |
| if ( getVersion( i ).equals( candidate ) ) { return true; } |
| } |
| |
| return false; |
| } |
| |
| /** |
| * <p> |
| * Return true if this Trajectory contains a version from the desired branch. |
| * </p> |
| */ |
| public boolean contains( String branchID ) |
| { |
| int count = getVersionCount(); |
| for ( int i = 0; i < count; i++ ) |
| { |
| if ( getVersion( i ).getBranchID().equals( branchID ) ) { return true; } |
| } |
| |
| return false; |
| } |
| |
| /** |
| * <p> |
| * Return true if this Trajectory ends at the desired Version. |
| * </p> |
| */ |
| public boolean endsAt( Version candidate ) |
| { |
| return ( getVersion( getVersionCount() - 1 ).equals( candidate ) ); |
| } |
| |
| /** |
| * <p> |
| * Return true if this Trajectory ends at the desired branch. |
| * </p> |
| */ |
| public boolean endsAt( String branchID ) |
| { |
| return ( getVersion( getVersionCount() - 1 ).getBranchID().equals( branchID ) ); |
| } |
| |
| public String toString() |
| { |
| StringBuffer buffer = new StringBuffer(); |
| int count = _versions.length; |
| |
| for ( int i = 0; i < count; i++ ) |
| { |
| if ( i > 0 ) { buffer.append( " -> " ); } |
| buffer.append( _versions[ i ].toString() ); |
| } |
| |
| return buffer.toString(); |
| } |
| |
| public int compareTo( Object other ) |
| { |
| if ( other == null ) { return -1; } |
| if ( !(other instanceof Trajectory) ) { return -1; } |
| |
| Trajectory that = (Trajectory) other; |
| int thisLength = this.getVersionCount(); |
| int thatLength = that.getVersionCount(); |
| int minLength = thisLength < thatLength ? thisLength : thatLength; |
| |
| for ( int i = 0; i < minLength; i++ ) |
| { |
| int result = this.getVersion( i ).compareTo( that.getVersion( i ) ); |
| if ( result != 0 ) { return result; } |
| } |
| |
| return thisLength - thatLength; |
| } |
| |
| public boolean equals( Object other ) { return ( compareTo( other ) == 0 ); } |
| |
| public int hashCode() { return toString().hashCode(); } |
| } |
| |
| |
| } |