All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.adobe.xmp.path.XMPPath Maven / Gradle / Ivy

// =================================================================================================
// ADOBE SYSTEMS INCORPORATED
// Copyright 2012 Adobe Systems Incorporated
// All Rights Reserved
//
// NOTICE:  Adobe permits you to use, modify, and distribute this file in accordance with the terms
// of the Adobe license agreement accompanying it.
// =================================================================================================
package com.adobe.xmp.path;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;

/**
 * XMPPath is a Class that provides an easy iterative description of a specific path into the XMP tree.
 * Each {@link XMPPathSegment} represents one segment of the path into the XMP tree.  
 */
public class XMPPath implements List 
{
	private List segments;

	public enum Compare
	{
		DIFFERENT, EQUAL, ANCESTOR, DESCENDANT
	}
	
	/**
	 * Creates an empty XMPPath object
	 */
	public XMPPath() 
	{
		// ArrayList is supposed to be faster than Vector, especially for iterations 
		segments = new ArrayList();
	}
	
	/**
	 * Creates an XMPPath object by parsing an XMP path String and creates one path segment 
	 * for each detected segment in the path.
	 * @param path Path string to parse
	 * @param prefixContract A Map that contains the mapping between Namespaces and their prefixes.
	 * This must be provided to interpret the path correctly. The key must be the prefix and the value the namespace!
	 * @throws XMPPathParserException If the path has an invalid format or a prefix is found that is not defined in the prefixContract
	 */
	public static XMPPath parse(String path, Map prefixContract ) throws XMPPathParserException
	{
		return XMPPathParser.parse( path, prefixContract );
	}
	
	/**
	 * Serializes the XMPPath object to a String representation.
	 * This will produce a long form of the path using the full namespace strings.
	 * @return String representation of the XMPPath
	 */
	public String serialize()
	{
		return serialize( null );
	}
	
	/**
	 * Serializes the XMPPath object to a String representation.
	 * This produces a short form of the path using the prefixes provided by the contract.
	 * @param prefixContract A Map that contains the mapping between Namespaces and their prefixes.
	 * The key must be the prefix and the value the namespace!
	 * @return String representation of the XMPPath
	 */
	public String serialize( Map prefixContract )
	{
		StringBuffer result = new StringBuffer();
		boolean firstSegment = true;
		
		for( XMPPathSegment segment : segments )
		{
			String prefix = null;
			
			if( prefixContract != null)
			{
				for( Entry entry : prefixContract.entrySet() )
				{
					if( entry.getValue().equals( segment.getNamespace() ) )
					{
						prefix = entry.getKey();
					}
				}
			}
			
			// if no prefix is available, use the full namespace string
			if(prefix == null)
			{
				prefix = segment.getNamespace();
			}
			
			switch( segment.getType() )
			{
				case PROPERTY:
					if( ! firstSegment )
					{
						result.append( "/" );
					}
					result.append( prefix + ":" + segment.getName());
					break;
				case ARRAY_INDEX:
					result.append( "[" + segment.getIndex() + "]" );
					break;
				case QUALIFIER:
					if( ! firstSegment )
					{
						result.append( "/" );
					}
					result.append( "@" + prefix + ":" + segment.getName() );
					break;
				case QUALIFIER_SELECTOR:
					result.append( "[?" + prefix + ":" + segment.getName() + "=\"" + segment.getValue() + "\"]" );
					break;
			}
			
			if( firstSegment )
			{
				firstSegment = false;
			}
		}
		
		return result.toString();
	}
	
	
	public int size()
	{
		return segments.size();
	}

	public boolean isEmpty()
	{
		return segments.isEmpty();
	}

	public boolean contains(Object o)
	{
		return segments.contains( o );
	}

	public Iterator iterator()
	{
		return segments.iterator();
	}

	public Object[] toArray()
	{
		return segments.toArray();
	}

	public  T[] toArray(T[] a)
	{
		return segments.toArray( a );
	}

	public boolean add(XMPPathSegment e)
	{
		return segments.add( e );
	}

	public boolean remove(Object o)
	{
		return segments.remove( o );
	}

	public boolean containsAll(Collection c)
	{
		return segments.containsAll( c );
	}

	public boolean addAll(Collection c)
	{
		return segments.addAll( c );
	}

	public boolean addAll(int index, Collection c)
	{
		return segments.addAll( index, c );
	}

	public boolean removeAll(Collection c)
	{
		return segments.removeAll( c );
	}

	public boolean retainAll(Collection c)
	{
		return segments.retainAll( c );
	}

	public void clear()
	{
		segments.clear();
	}

	public XMPPathSegment get(int index)
	{
		return segments.get( index );
	}

	public XMPPathSegment set(int index, XMPPathSegment element)
	{
		return segments.set( index, element );
	}

	public void add(int index, XMPPathSegment element)
	{
		segments.add( index, element );
	}

	public XMPPathSegment remove(int index)
	{
		return segments.remove( index );
	}

	public int indexOf(Object o)
	{
		return segments.indexOf( o );
	}

	public int lastIndexOf(Object o)
	{
		return segments.lastIndexOf( o );
	}

	public ListIterator listIterator()
	{
		return segments.listIterator();
	}

	public ListIterator listIterator(int index)
	{
		return segments.listIterator( index );
	}

	public List subList(int fromIndex, int toIndex)
	{
		return segments.subList( fromIndex, toIndex );
	}

	/**
	 * Compares the provided path with this path.
	 * 
	 * @param path the path to compare with
	 * @return The paths are equal if both have the same size and each segment is EQUAL.
	 * If the provided path is a subpath of this path, ANCESTOR is returned.
	 * If the provided path is an ancestor of this path, DESCENDANT is returned.
	 * In all other cases the paths are DIFFERENT.
	 * @throws IllegalArgumentException If path is null
	 */
	public Compare compare(XMPPath path) 
	{
		if( path == null )
		{
			throw new IllegalArgumentException("path must not be null");
		}
		
		if( this.size() == 0 && path.size() == 0 )
		{
			return Compare.EQUAL;
		}
		else if( this.size() == 0 && path.size() != 0 || 
				this.size() != 0 && path.size() == 0 )
		{
			return Compare.DIFFERENT;
		}
		
		ListIterator pathIter = this.listIterator();
		ListIterator otherPathIter = path.listIterator();
		
		while( pathIter.hasNext() )
		{
			if( otherPathIter.hasNext() )
			{
				if( ! pathIter.next().equals(otherPathIter.next()) )
				{
					return Compare.DIFFERENT;
				}
			}
			else
			{
				return Compare.DESCENDANT;
			}
		}
		
		if( otherPathIter.hasNext() )
		{
			return Compare.ANCESTOR;
		}
		
		return Compare.EQUAL;
	}

	@Override
	public int hashCode() 
	{
		final int prime = 31;
		int result = 1;
		result = prime * result	+ ((segments == null) ? 0 : segments.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) 
	{
		if (this == obj)
		{
			return true;
		}
		if (obj == null)
		{
			return false;
		}
		if (getClass() != obj.getClass())
		{
			return false;
		}
		XMPPath other = (XMPPath) obj;
		if (segments == null) 
		{
			if (other.segments != null)
			{
				return false;
			}
		} 
		else if (!segments.equals(other.segments))
		{
			return false;
		}
		return true;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy