/*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* Copyright (c) 2006 - 2013 Pentaho Corporation and Contributors. All rights reserved.
*/
package org.pentaho.reporting.libraries.resourceloader;
import org.pentaho.reporting.libraries.base.util.ObjectUtilities;
import java.io.File;
import java.io.Serializable;
import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* The key is an unique identifier for the resource. Most of the time, this may be an URL, but other (especially
* database based) schemas are possible.
* <p/>
* A resource key must provide an 'equals' implementation. ResourceKeys should be implemented as immutable classes, so
* that they can be safely stored in collections or on external storages (like caches).
*
* @author Thomas Morgner
*/
public final class ResourceKey implements Serializable {
/**
* @noinspection StaticCollection
*/
private static final Map<ParameterKey, Object> EMPTY_MAP = Collections.emptyMap();
private static final long serialVersionUID = -7764107570068726772L;
private Map<? extends ParameterKey, Object> factoryParameters;
private Integer hashCode;
private Object schema;
private Object identifier;
private ResourceKey parent;
public ResourceKey( final Object schema,
final Object identifier,
final Map<? extends ParameterKey, Object> factoryParameters ) {
if ( schema == null ) {
throw new NullPointerException();
}
if ( identifier == null ) {
throw new NullPointerException();
}
this.schema = schema;
this.identifier = identifier;
if ( factoryParameters != null ) {
this.factoryParameters =
Collections.unmodifiableMap( new LinkedHashMap<ParameterKey, Object>( factoryParameters ) );
} else {
this.factoryParameters = EMPTY_MAP;
}
}
public ResourceKey( final ResourceKey parent,
final Object schema,
final Object identifier,
final Map<? extends ParameterKey, Object> factoryParameters ) {
this( schema, identifier, factoryParameters );
this.parent = parent;
}
public static ResourceKey createAsDerived( final ResourceKey parent,
final ResourceKey child ) {
if ( child.parent != null ) {
throw new IllegalArgumentException();
}
return new ResourceKey( parent, child.schema, child.identifier, child.factoryParameters );
}
public ResourceKey getParent() {
return parent;
}
public Map<ParameterKey, Object> getFactoryParameters() {
return Collections.unmodifiableMap( factoryParameters );
}
public boolean equals( final Object o ) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
final ResourceKey that = (ResourceKey) o;
if ( that.hashCode != null && this.hashCode != null ) {
// shortcut: If the hashcode is not equal, the whole object cannot be equal
// see contract of equals/hashcode for details.
if ( that.hashCode.equals( this.hashCode ) == false ) {
return false;
}
}
if ( parent != that.parent && ObjectUtilities.equal( parent, that.parent ) == false ) {
return false;
}
if ( !schema.equals( that.schema ) ) {
return false;
}
if ( !factoryParameters.equals( that.factoryParameters ) ) {
return false;
}
if ( identifier instanceof URL ) {
if ( String.valueOf( identifier ).equals( String.valueOf( that.identifier ) ) == false ) {
return false;
}
} else if ( identifier instanceof File && that.identifier instanceof File ) {
// File.equals() does not check to see if two File objects refer to the same file ...
// it checks to make sure they refer to the same file IN THE SAME way (which is deeper than we need)
if ( ObjectUtilities.equals( (File) identifier, (File) that.identifier ) == false ) {
return false;
}
} else if ( !identifier.equals( that.identifier ) ) {
if ( identifier instanceof byte[] && that.identifier instanceof byte[] ) {
final byte[] me = (byte[]) identifier;
final byte[] he = (byte[]) that.identifier;
if ( Arrays.equals( me, he ) == false ) {
return false;
}
} else {
return false;
}
}
return true;
}
public int hashCode() {
if ( hashCode == null ) {
int result = factoryParameters.hashCode();
result = 29 * result + schema.hashCode();
if ( identifier instanceof URL ) {
final URL url = (URL) identifier;
result = 29 * result + url.toString().hashCode();
} else if ( identifier instanceof byte[] ) {
result = 29 * result + Arrays.hashCode( (byte[]) identifier );
} else {
result = 29 * result + identifier.hashCode();
}
if ( parent != null ) {
result = 29 * result + parent.hashCode();
}
hashCode = ( result );
}
return hashCode.intValue();
}
public Object getIdentifier() {
return identifier;
}
/**
* Returns a String version of the identifier.
*
* @return the identifier as string or null, if the identifier could not be converted easily.
*/
public String getIdentifierAsString() {
if ( identifier instanceof File ) {
final File file = (File) identifier;
return file.getPath();
}
if ( identifier instanceof URL ) {
final URL url = (URL) identifier;
return url.toExternalForm();
}
if ( identifier instanceof String ) {
return identifier.toString();
}
return null;
}
/**
* Returns the schema of this resource key. The schema is an internal identifier to locate the resource-loader
* implementation that was responsible for creating the key in the first place.
* <p/>
* The schema has no meaning outside the resource loading framework.
*
* @return
*/
public Object getSchema() {
return schema;
}
public String toString() {
return "ResourceKey{" +
"schema=" + schema +
", identifier=" + identifier +
", factoryParameters=" + factoryParameters +
", parent=" + parent +
'}';
}
}