/** * Copyright 2007-2008 University Of Southern California * * Licensed 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 edu.isi.pegasus.planner.classes; import edu.isi.pegasus.planner.catalog.replica.ReplicaCatalogEntry; import edu.isi.pegasus.planner.dax.PFN; import edu.isi.pegasus.planner.namespace.Metadata; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.ArrayList; /** * A Data Class that associates a LFN with the PFN's. Attributes associated * with the LFN go here. * * @author Karan Vahi * @author Gaurang Mehta * * @version $Revision$ * * @see edu.isi.pegasus.planner.catalog.replica.ReplicaCatalogEntry */ public class ReplicaLocation extends Data implements Cloneable{ /** * The site name that is associated in the case the resource handle is not * specified with the PFN. */ public static final String UNDEFINED_SITE_NAME = "UNDEFINED_SITE"; /** * The LFN associated with the entry. */ private String mLFN; /** * A list of <code>ReplicaCatalogEntry</code> objects containing the PFN's * and associated attributes. */ private List<ReplicaCatalogEntry> mPFNList; /** * Metadata attributes associated with the file. */ private Metadata mMetadata; /** * Default constructor. */ public ReplicaLocation(){ this( "", new ArrayList<ReplicaCatalogEntry>()); } /** * Overloaded constructor. * Initializes the member variables to the values passed. * * @param rl */ public ReplicaLocation( ReplicaLocation rl ){ this( rl.getLFN(), rl.getPFNList() ); } /** * Overloaded constructor. * Initializes the member variables to the values passed. * * @param lfn the logical filename. * @param pfns the list of <code>ReplicaCatalogEntry</code> objects. */ public ReplicaLocation( String lfn , Collection<ReplicaCatalogEntry> pfns ){ mLFN = lfn; mMetadata = this.removeMetadata( pfns ); //PM-1001 always create a separate list only if required mPFNList = new ArrayList( pfns ) ; //sanitize pfns. add a default resource handle if not specified sanitize( mPFNList ); } /** * Adds a PFN specified in the DAX to the object * * @param pfn the PFN */ public void addPFN(PFN pfn) { ReplicaCatalogEntry rce = new ReplicaCatalogEntry( ); rce.setPFN( pfn.getURL() ); rce.setResourceHandle( pfn.getSite() ); this.mPFNList.add( rce ); } /** * Add a PFN and it's attributes. Any existing * mapping with the same PFN and site attribute will be replaced, including all its * attributes. * * @param tuples the collection of <code>ReplicaCatalogEntry</code> object containing the * PFN and the attributes. */ public void addPFN( Collection<ReplicaCatalogEntry> tuples ){ for( ReplicaCatalogEntry tuple: tuples ){ this.addPFN(tuple); } } /** * Add a PFN and it's attributes. Any existing * mapping with the same PFN and site attribute will be replaced, including all its * attributes. * * @param tuple the <code>ReplicaCatalogEntry</code> object containing the * PFN and the attributes. */ public void addPFN( ReplicaCatalogEntry tuple ){ boolean seen = false; String pfn = tuple.getPFN(); String site = tuple.getResourceHandle(); sanitize( tuple ); //traverse through the existing PFN's to check for the //same pfn for ( Iterator i= this.pfnIterator(); i.hasNext() && ! seen; ) { ReplicaCatalogEntry rce = (ReplicaCatalogEntry) i.next(); seen = pfn.equals(rce.getPFN()) && site.equals( rce.getResourceHandle() ); if ( seen ) { try { i.remove(); } catch ( UnsupportedOperationException uoe ) { //ignore for time being } } } this.mPFNList.add( tuple ); } /** * Add a PFN and it's attributes. * * @param tuples the <code>List</code> object of <code>ReplicaCatalogEntry</code> * objects, each containing the PFN and the attributes. */ protected void addPFNs( List<ReplicaCatalogEntry> tuples ){ for( Iterator it = tuples.iterator(); it.hasNext(); ){ addPFN( (ReplicaCatalogEntry)it.next() ); } } /** * Add metadata to the object. * * @param key * @param value */ public void addMetadata( String key, String value ){ this.mMetadata.checkKeyInNS( key, value ); } /** * Sets the LFN. * * @param lfn the lfn. */ public void setLFN( String lfn ){ this.mLFN = lfn; } /** * Returns the associated LFN. * * @return lfn */ public String getLFN( ){ return this.mLFN; } /** * Return a PFN as a <code>ReplicaCatalogEntry</code> * * @param index the pfn location. * * @return the element at the specified position in this list. * * @throws IndexOutOfBoundsException - if the index is out of range (index < 0 || index >= size()). */ public ReplicaCatalogEntry getPFN( int index ){ return (ReplicaCatalogEntry)this.mPFNList.get( index ); } /** * Returns the list of pfn's as <code>ReplicaCatalogEntry</code> objects. * * @return List */ public List<ReplicaCatalogEntry> getPFNList( ){ return this.mPFNList; } /** * Returns an iterator to the list of <code>ReplicaCatalogEntry</code> * objects. * * @return Iterator. */ public Iterator pfnIterator(){ return this.mPFNList.iterator(); } /** * Returns the number of pfn's associated with the lfn. * * @return int */ public int getPFNCount(){ return this.mPFNList.size(); } /** * Returns metadata attribute for a particular key * * @param key * * @return value returned else null if not found */ public String getMetadata( String key ){ return (String)mMetadata.get( key ); } /** * Returns all metadata attributes for the file * * @return Metadata */ public Metadata getAllMetadata( ){ return this.mMetadata; } /** * Returns the clone of the object. * * @return the clone */ public Object clone(){ ReplicaLocation rc; try{ rc = ( ReplicaLocation ) super.clone(); } catch( CloneNotSupportedException e ){ //somewhere in the hierarch chain clone is not implemented throw new RuntimeException("Clone not implemented in the base class of " + this.getClass().getName(), e ); } rc.mPFNList = new ArrayList(); rc.setLFN( this.mLFN ); rc.mMetadata = (Metadata) this.mMetadata.clone(); //add all the RCE's for( Iterator it = this.pfnIterator(); it.hasNext(); ){ //creating a shallow clone here. rc.addPFN( ( ReplicaCatalogEntry )it.next() ); } //clone is not implemented fully. //throw new RuntimeException( "Clone not implemented for " + this.getClass().getName() ); return rc; } /** * Merges the <code>ReplicaLocation</code> object to the existing one, * only if the logical filenames match. * * @param location is another <code>ReplicaLocations</code> to merge with. * * @return true if a merge was successful, false if the LFNs did not * match. */ public boolean merge(ReplicaLocation location){ String lfn1 = this.getLFN(); String lfn2 = (location == null)? null : location.getLFN(); boolean result = (lfn1 == null && lfn2 == null || lfn1 != null && lfn2 != null && lfn1.equals(lfn2)); // only merge if LFN match if (result) { this.addPFNs( location.getPFNList() ); for( Iterator it = location.getAllMetadata().getProfileKeyIterator(); it.hasNext();){ String key = (String)it.next(); this.addMetadata( key, location.getMetadata(key)); } } return result; } /** * Returns the textual description of the data class. * * @return the textual description. */ public String toString(){ StringBuffer sb = new StringBuffer(); sb.append( mLFN ).append( " -> {"); for( Iterator it = this.pfnIterator(); it.hasNext(); ){ sb.append( it.next() ); sb.append( "," ); } sb.append( this.getAllMetadata() ); sb.append( "}" ); return sb.toString(); } /** * Helper method to retrofit RCE into the metadata object * For replica catalog, metadata is per LFN * * @param rces * * @return Metadata object */ protected final Metadata removeMetadata( Collection<ReplicaCatalogEntry> rces ){ Metadata m = new Metadata(); for( ReplicaCatalogEntry rce: rces ){ for(Iterator<String> it = rce.getAttributeIterator(); it.hasNext(); ){ String attribute = it.next(); if( attribute.equals( ReplicaCatalogEntry.RESOURCE_HANDLE) || attribute.equals( ReplicaCatalogEntry.DEPRECATED_RESOURCE_HANDLE ) ){ //skip continue; } m.construct(attribute, (String) rce.getAttribute( attribute)); it.remove(); } } return m; } /** * Sanitizes a tuple list . Sets the resource handle to a default value if not * specified. * * @param tuples the tuple to be sanitized. */ private void sanitize( List tuples ){ for( Iterator it = tuples.iterator(); it.hasNext(); ){ this.sanitize( (ReplicaCatalogEntry)it.next() ); } } /** * Sanitizes a tuple . Sets the resource handle to a default value if not * specified. * * @param tuple the tuple to be sanitized. */ private void sanitize( ReplicaCatalogEntry tuple ){ //sanity check if( tuple.getResourceHandle() == null ){ tuple.setResourceHandle( this.UNDEFINED_SITE_NAME ); } } }