Skip to Content.
Sympa Menu

notify-dpml - r1833 - in trunk/main/transit/core/src/main/dpml: transit transit/artifact transit/info transit/link transit/local util

notify-dpml AT lists.ibiblio.org

Subject: DPML Notify

List archive

Chronological Thread  
  • From: mcconnell at BerliOS <mcconnell AT mail.berlios.de>
  • To: notify-dpml AT lists.ibiblio.org
  • Subject: r1833 - in trunk/main/transit/core/src/main/dpml: transit transit/artifact transit/info transit/link transit/local util
  • Date: Fri, 9 Feb 2007 00:43:14 +0100

Author: mcconnell
Date: 2007-02-09 00:42:59 +0100 (Fri, 09 Feb 2007)
New Revision: 1833

Added:
trunk/main/transit/core/src/main/dpml/transit/Cache.java
trunk/main/transit/core/src/main/dpml/transit/ConnectionCache.java
trunk/main/transit/core/src/main/dpml/transit/DefaultCacheHandler.java
trunk/main/transit/core/src/main/dpml/transit/DefaultMonitor.java
trunk/main/transit/core/src/main/dpml/transit/DefaultResourceHost.java
trunk/main/transit/core/src/main/dpml/transit/DelegatingAuthenticator.java
trunk/main/transit/core/src/main/dpml/transit/Host.java
trunk/main/transit/core/src/main/dpml/transit/NetworkLoader.java
trunk/main/transit/core/src/main/dpml/transit/PropertyUtils.java
trunk/main/transit/core/src/main/dpml/transit/RequestIdentifier.java
trunk/main/transit/core/src/main/dpml/transit/StandardLinkManager.java
trunk/main/transit/core/src/main/dpml/transit/StandardMonitor.java
trunk/main/transit/core/src/main/dpml/transit/StreamUtils.java
trunk/main/transit/core/src/main/dpml/transit/TransitAuthenticator.java
trunk/main/transit/core/src/main/dpml/transit/TransitAuthenticatorImpl.java
trunk/main/transit/core/src/main/dpml/transit/TransitContext.java
trunk/main/transit/core/src/main/dpml/transit/ZipCache.java
trunk/main/transit/core/src/main/dpml/transit/artifact/
trunk/main/transit/core/src/main/dpml/transit/artifact/MimeTypeHandler.java
trunk/main/transit/core/src/main/dpml/transit/artifact/package-info.java
trunk/main/transit/core/src/main/dpml/transit/info/
trunk/main/transit/core/src/main/dpml/transit/info/DTD.java
trunk/main/transit/core/src/main/dpml/transit/info/DTDResolver.java
trunk/main/transit/core/src/main/dpml/transit/info/SaxMonitor.java
trunk/main/transit/core/src/main/dpml/transit/info/TransitDecoder.java
trunk/main/transit/core/src/main/dpml/transit/info/TransitEncoder.java
trunk/main/transit/core/src/main/dpml/transit/info/package-info.java
trunk/main/transit/core/src/main/dpml/transit/link/
trunk/main/transit/core/src/main/dpml/transit/link/package-info.java
trunk/main/transit/core/src/main/dpml/transit/local/
trunk/main/transit/core/src/main/dpml/transit/local/package-info.java
trunk/main/transit/core/src/main/dpml/transit/package-info.java
trunk/main/transit/core/src/main/dpml/util/CLIHelper.java
trunk/main/transit/core/src/main/dpml/util/Category.java
trunk/main/transit/core/src/main/dpml/util/ConfigurationHandler.java
trunk/main/transit/core/src/main/dpml/util/DefaultLogger.java
trunk/main/transit/core/src/main/dpml/util/DepotHandler.java
trunk/main/transit/core/src/main/dpml/util/DepotLoggingConfiguration.java
trunk/main/transit/core/src/main/dpml/util/ElementHelper.java
trunk/main/transit/core/src/main/dpml/util/ExceptionHelper.java
trunk/main/transit/core/src/main/dpml/util/FederatingClassLoader.java
trunk/main/transit/core/src/main/dpml/util/LogStatement.java
trunk/main/transit/core/src/main/dpml/util/LoggingService.java
trunk/main/transit/core/src/main/dpml/util/Main.java
trunk/main/transit/core/src/main/dpml/util/ObjectUtils.java
trunk/main/transit/core/src/main/dpml/util/PID.java
trunk/main/transit/core/src/main/dpml/util/PropertyResolver.java
trunk/main/transit/core/src/main/dpml/util/SimpleResolver.java
trunk/main/transit/core/src/main/dpml/util/StandardClassLoader.java
trunk/main/transit/core/src/main/dpml/util/StandardFormatter.java
trunk/main/transit/core/src/main/dpml/util/SystemClassLoader.java
trunk/main/transit/core/src/main/dpml/util/package-info.java
Removed:

trunk/main/transit/core/src/main/dpml/transit/artifact/ArtifactAlreadyExistsException.java

trunk/main/transit/core/src/main/dpml/transit/artifact/ArtifactException.java

trunk/main/transit/core/src/main/dpml/transit/artifact/ArtifactNotFoundException.java
trunk/main/transit/core/src/main/dpml/transit/artifact/package.html
trunk/main/transit/core/src/main/dpml/transit/info/CodeBaseDirective.java
trunk/main/transit/core/src/main/dpml/transit/info/LayoutDirective.java
trunk/main/transit/core/src/main/dpml/transit/info/package.html
trunk/main/transit/core/src/main/dpml/transit/link/ArtifactLinkManager.java
trunk/main/transit/core/src/main/dpml/transit/link/Link.java
trunk/main/transit/core/src/main/dpml/transit/link/LinkManager.java

trunk/main/transit/core/src/main/dpml/transit/link/LinkNotFoundException.java
trunk/main/transit/core/src/main/dpml/transit/link/package.html
trunk/main/transit/core/src/main/dpml/transit/local/package.html
Modified:

trunk/main/transit/core/src/main/dpml/transit/artifact/ArtifactURLConnection.java
trunk/main/transit/core/src/main/dpml/transit/artifact/Handler.java
trunk/main/transit/core/src/main/dpml/transit/info/CacheDirective.java
trunk/main/transit/core/src/main/dpml/transit/info/HostDirective.java
trunk/main/transit/core/src/main/dpml/transit/info/ProxyDirective.java
trunk/main/transit/core/src/main/dpml/transit/info/TransitDirective.java
trunk/main/transit/core/src/main/dpml/transit/link/Handler.java
trunk/main/transit/core/src/main/dpml/transit/link/LinkURLConnection.java
trunk/main/transit/core/src/main/dpml/transit/local/Handler.java
trunk/main/transit/core/src/main/dpml/transit/local/LocalURLConnection.java
Log:
SDK 2.X staged commit.

Added: trunk/main/transit/core/src/main/dpml/transit/Cache.java
===================================================================
--- trunk/main/transit/core/src/main/dpml/transit/Cache.java 2007-02-08
23:39:34 UTC (rev 1832)
+++ trunk/main/transit/core/src/main/dpml/transit/Cache.java 2007-02-08
23:42:59 UTC (rev 1833)
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2004-2007 Stephen J. McConnell.
+ *
+ * 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 dpml.transit;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import net.dpml.transit.Artifact;
+import net.dpml.transit.Layout;
+import net.dpml.transit.TransitException;
+import net.dpml.transit.ArtifactAlreadyExistsException;
+
+/**
+ * Cache service SPI for protocol handlers. Cache services
+ * encompass the retreval of resources based on artifact identifiers. A
cache
+ * handler implementations may provide varying levels of quality-of-services.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public interface Cache
+{
+ /**
+ * Return the layout used by the cache.
+ * @return the cache layout
+ */
+ Layout getLayout();
+
+ /**
+ * Return the cache directory.
+ * @return the cache directory.
+ */
+ File getCacheDirectory();
+
+ /**
+ * Return the cache directory.
+ * @param artifact the artifact to resolve
+ * @return the working cache directory
+ * @exception IOException if an IO error occurs
+ */
+ File getLocalFile( Artifact artifact ) throws IOException;
+
+ /**
+ * Attempts to download and cache a remote artifact using a set of remote
+ * repositories.
+ *
+ * @param artifact the artifact to retrieve and cache
+ * @return an input stream to the local resource
+ * @exception IOException if an IO error occurs
+ * @exception TransitException is a transit system error occurs
+ */
+ InputStream getResource( Artifact artifact )
+ throws IOException, TransitException;
+
+ /**
+ * Attempts to download and cache a remote artifact using a set of remote
+ * repositories.
+ * <p>
+ * This method allows an internal reference to be passed to the
+ * cache handler and it is expected to return the InputStream of the
+ * internal item inside Jar/Zip files. If this method is called, the
+ * implementation can assume that the artifact is a Zip file.
+ * </p>
+ *
+ * @param artifact the artifact to retrieve and cache
+ * @param resource referencing a item within the artifact. This
+ * argument may start with "!" or "!/", which should be ignored.
+ * @return a file referencing the local resource
+ * @exception IOException if an IO error occurs
+ * @exception TransitException is a transit system error occurs
+ */
+ InputStream getResource( Artifact artifact, String resource )
+ throws IOException, TransitException;
+
+ /**
+ * Creates an output stream to where the artifact content can be written
+ * to.
+ * <p>
+ * If the artifact already exists, a
<code>ArtifactAlreadyExistsException</code>
+ * will be thrown. If the directory doesn't exists, it will be created.
+ * The CacheHandler is responsible to recognize the completion of the
+ * writes through the <code>close()</code> method in the output stream,
+ * and do any post-processing there.
+ * </p>
+ * @param artifact the artifact
+ * @return an output stream
+ * @exception ArtifactAlreadyExistsException if the artifact already
exists in the cache.
+ * @exception IOException if an IO error occurs
+ */
+ OutputStream createOutputStream( Artifact artifact )
+ throws ArtifactAlreadyExistsException, IOException;
+
+}

Added: trunk/main/transit/core/src/main/dpml/transit/ConnectionCache.java
===================================================================
--- trunk/main/transit/core/src/main/dpml/transit/ConnectionCache.java
2007-02-08 23:39:34 UTC (rev 1832)
+++ trunk/main/transit/core/src/main/dpml/transit/ConnectionCache.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2004-2005 Stephen J. McConnell.
+ * Copyright 2004 Niclas Hedhman
+ * 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 dpml.transit;
+
+import java.net.URLConnection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.WeakHashMap;
+
+import net.dpml.transit.Artifact;
+
+/**
+ * Internal cache for url connections.
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+final class ConnectionCache implements Runnable
+{
+ private static final Object DUMMY = new Object();
+ private static final long TIME_TO_LIVE = 30000;
+ private static final int PAUSE_DELAY = 10000;
+ private static ConnectionCache m_INSTANCE;
+
+ private final HashMap<Artifact, Entry> m_hardStore;
+ private final WeakHashMap<URLConnection, Object> m_weakStore;
+ private Thread m_thread;
+
+ static
+ {
+ m_INSTANCE = new ConnectionCache();
+ }
+
+ /**
+ * Return the connection cacne instance.
+ * @return the singleton instance
+ */
+ public static ConnectionCache getInstance()
+ {
+ return m_INSTANCE;
+ }
+
+ /**
+ * Internal constructor of the connection cache.
+ */
+ private ConnectionCache()
+ {
+ m_hardStore = new HashMap<Artifact, Entry>();
+ m_weakStore = new WeakHashMap<URLConnection, Object>();
+ }
+
+ /**
+ * Return the cached url connnection for an artifact.
+ * @param key the arfifact
+ * @return the cached url connection or null if not cached
+ */
+ public URLConnection get( Artifact key )
+ {
+ synchronized( this ) // ensure no ConcurrentModificationException
can occur.
+ {
+ Entry entry = m_hardStore.get( key );
+ if( entry == null )
+ {
+ return null;
+ }
+ URLConnection conn = entry.m_connection;
+ return conn;
+ }
+ }
+
+ /**
+ * Put a connection into the cache.
+ * @param key the artifact to be used as the cache key
+ * @param conn the url connection to cache
+ */
+ public void put( Artifact key, URLConnection conn )
+ {
+ synchronized( this ) // ensure no ConcurrentModificationException
can occur.
+ {
+ Entry entry = new Entry( conn );
+ m_hardStore.put( key, entry );
+ if( m_thread == null )
+ {
+ m_thread = new Thread( this, "ConnectionCache-cleaner" );
+ m_thread.setDaemon( true );
+ m_thread.start();
+ }
+ }
+ }
+
+ /**
+ * Start the cache.
+ */
+ public void run()
+ {
+ while( true )
+ {
+ try
+ {
+ synchronized( this )
+ {
+ long now = System.currentTimeMillis();
+ Iterator list = m_hardStore.values().iterator();
+ while( list.hasNext() )
+ {
+ Entry entry = (Entry) list.next();
+ if( entry.m_collectTime < now )
+ {
+ m_weakStore.put( entry.m_connection, DUMMY );
+ list.remove();
+ }
+ }
+ if( m_hardStore.size() == 0 )
+ {
+ m_thread = null; // mark to start a new thread
next time.
+ break; // Exit the thread
+ }
+ wait( PAUSE_DELAY );
+ }
+ }
+ catch( Exception e )
+ {
+ // Can not happen?
+ // Just ignore and it will be handled in the next round.
+ e.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * Internal class used for cache entries.
+ */
+ private class Entry
+ {
+ private final URLConnection m_connection;
+ private final long m_collectTime;
+
+ /**
+ * Creation of a new cache entry instance.
+ * @param conn the url connection
+ */
+ Entry( URLConnection conn )
+ {
+ m_connection = conn;
+ m_collectTime = System.currentTimeMillis() + TIME_TO_LIVE;
+ }
+
+ /**
+ * Test for equality.
+ * @param obj the other object
+ * @return the equality status
+ */
+ public boolean equals( Object obj )
+ {
+ if( obj == null )
+ {
+ return false;
+ }
+ if( !obj.getClass().equals( Entry.class ) )
+ {
+ return false;
+ }
+ Entry other = (Entry) obj;
+ if( !m_connection.equals( other.m_connection ) )
+ {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Return the hashcode for the instance.
+ * @return the hashcode
+ */
+ public int hashCode()
+ {
+ return m_connection.hashCode();
+ }
+
+ /**
+ * Return the string representation of the instance.
+ * @return the string
+ */
+ public String toString()
+ {
+ return "Entry[" + m_connection + ", " + m_collectTime + "]";
+ }
+ }
+}

Added: trunk/main/transit/core/src/main/dpml/transit/DefaultCacheHandler.java
===================================================================
--- trunk/main/transit/core/src/main/dpml/transit/DefaultCacheHandler.java
2007-02-08 23:39:34 UTC (rev 1832)
+++ trunk/main/transit/core/src/main/dpml/transit/DefaultCacheHandler.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,630 @@
+/*
+ * Copyright 2004-2007 Stephen J. McConnell.
+ * Copyright 2004 Niclas Hedhman.
+ *
+ * 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 dpml.transit;
+
+import dpml.util.PropertyResolver;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Properties;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Hashtable;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.Comparator;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.MBeanException;
+
+import net.dpml.transit.Artifact;
+import net.dpml.transit.CacheManager;
+import net.dpml.transit.Layout;
+import net.dpml.transit.HostManager;
+import net.dpml.transit.Transit;
+import net.dpml.transit.TransitException;
+import net.dpml.transit.ArtifactAlreadyExistsException;
+import net.dpml.transit.ArtifactNotFoundException;
+import net.dpml.transit.Monitor;
+
+import dpml.transit.info.CacheDirective;
+import dpml.transit.info.HostDirective;
+
+import net.dpml.util.Logger;
+
+import static net.dpml.transit.Transit.DATA;
+
+/**
+ * Default cache handler that maintains a file based cache.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+class DefaultCacheHandler implements Cache, CacheManager
+{
+ //
------------------------------------------------------------------------
+ // state
+ //
------------------------------------------------------------------------
+
+ /**
+ * The immutable cache configuration.
+ */
+ private final CacheDirective m_directive;
+
+ /**
+ * The cache base directory.
+ */
+ private File m_cacheDir;
+
+ /**
+ * The resource hosts.
+ */
+ private TreeSet<Host> m_resourceHosts = new TreeSet<Host>();
+
+ /**
+ * The cache layout strategy.
+ */
+ private Layout m_layout;
+
+ /**
+ * Internal zip file cache.
+ */
+ private ZipCache m_zipCache;
+
+ /**
+ * Internal logger.
+ */
+ private final Logger m_logger;
+
+ private final TransitContext m_context;
+
+ //
------------------------------------------------------------------------
+ // constructor
+ //
------------------------------------------------------------------------
+
+ /**
+ * Creation of a new file based cache controller using a supplied
+ * configuration model.
+ *
+ * @param server JMX server (may be null)
+ * @param directive the cache configuration directive
+ * @param logger the assigned logging channel
+ * @exception IOException if an IO error occurs
+ */
+ DefaultCacheHandler(
+ MBeanServer server, TransitContext context, CacheDirective directive,
Logger logger ) throws Exception
+ {
+ super();
+
+ m_directive = directive;
+ m_logger = logger;
+ m_context = context;
+
+ m_zipCache = new ZipCache();
+
+ String key = directive.getCacheLayout();
+ m_layout = Layout.getLayout( key );
+ if( getLogger().isTraceEnabled() )
+ {
+ getLogger().trace( "cache initialization" );
+ }
+
+ HostDirective local = createLocalHostDirective( directive );
+ Host system = createDefaultResourceHost( local );
+ m_resourceHosts.add( system );
+
+ HostDirective[] hosts = directive.getHostDirectives();
+ if( getLogger().isTraceEnabled() )
+ {
+ getLogger().trace( "host count: " + hosts.length );
+ }
+ for( int i=0; i < hosts.length; i++ )
+ {
+ HostDirective host = hosts[i];
+ String id = host.getID();
+ Host handler = createDefaultResourceHost( host );
+ m_resourceHosts.add( handler );
+ }
+
+ //
+ // setup the cache directory
+ //
+
+ String path = directive.getCache();
+ File cache = resolveCacheDirectory( path );
+ cache.mkdirs();
+ m_cacheDir = cache;
+
+ if( logger.isTraceEnabled() )
+ {
+ logger.trace( "setting cache: " + cache );
+ }
+
+ if( null != server )
+ {
+ Hashtable<String, String> table = new Hashtable<String,
String>();
+ table.put( "type", "Cache" );
+ ObjectName name =
+ ObjectName.getInstance( "net.dpml.transit", table );
+ server.registerMBean( this, name );
+
+ HostManager[] hostManagers = getHosts();
+ for( int i=0; i < hostManagers.length; i++ )
+ {
+ HostManager host = hostManagers[i];
+ registerHostManager( server, host );
+ }
+ }
+
+ if( getLogger().isTraceEnabled() )
+ {
+ getLogger().trace( "cache initialization complete" );
+ }
+ }
+
+ private void registerHostManager(
+ final MBeanServer server, final HostManager host ) throws Exception
+ {
+ String id = host.getID();
+ Hashtable<String, String> table = new Hashtable<String, String>();
+ table.put( "type", "Cache" );
+ table.put( "name", id );
+ ObjectName name =
+ ObjectName.getInstance( "net.dpml.transit", table );
+ server.registerMBean( host, name );
+ }
+
+ private File resolveCacheDirectory( final String path )
+ {
+ Properties properties = System.getProperties();
+ String resolved = PropertyResolver.resolve( properties, path );
+ File cache = new File( resolved );
+ if( !cache.isAbsolute() )
+ {
+ File anchor = Transit.DATA;
+ return new File( anchor, resolved );
+ }
+ else
+ {
+ return cache;
+ }
+ }
+
+ /**
+ * Return a file referencing the the locally cached resource.
+ *
+ * @return the cached file
+ */
+ public File getLocalFile( Artifact artifact ) throws IOException
+ {
+ File cache = getCacheDirectory();
+ String name = m_layout.resolvePath( artifact );
+ return new File( cache, name );
+ }
+
+ //
------------------------------------------------------------------------
+ // CacheManager
+ //
------------------------------------------------------------------------
+
+ public String getPath()
+ {
+ return m_directive.getCache();
+ }
+
+ /**
+ * Return the current cache directory.
+ * @return the cache directory.
+ */
+ public String getDirectory()
+ {
+ try
+ {
+ return m_cacheDir.getCanonicalPath();
+ }
+ catch( IOException e )
+ {
+ return m_cacheDir.toString();
+ }
+ }
+
+ /**
+ * Return the Transit cache layout id.
+ * @return the cache layout identifier
+ */
+ public String getLayoutID()
+ {
+ return getLayout().getID();
+ }
+
+ public HostManager[] getHosts()
+ {
+ return (HostManager[]) m_resourceHosts.toArray( new HostManager[0]
);
+ }
+
+ //
------------------------------------------------------------------------
+ // CacheHandler
+ //
------------------------------------------------------------------------
+
+ /**
+ * Return the current cache directory.
+ * @return the cache directory.
+ */
+ public File getCacheDirectory()
+ {
+ return m_cacheDir;
+ }
+
+ /**
+ * Attempts to download and cache a remote artifact using a set of remote
+ * repositories. The operation is not fail fast and so it keeps trying if
+ * the first repository does not have the artifact in question.
+ *
+ * @param artifact the artifact to retrieve and cache
+ * @return input stream containing the artifact content.
+ * @exception IOException if an IO error occurs.
+ * @exception TransitException if a transit system error occurs.
+ * @exception NullPointerException if the artifact argument is null.
+ */
+ public InputStream getResource( Artifact artifact )
+ throws IOException, TransitException, NullPointerException
+ {
+ File destination = getResourceFile( artifact );
+
+ if( destination.exists() )
+ {
+ FileInputStream stream = new FileInputStream( destination );
+ return new BufferedInputStream( stream );
+ }
+
+ String error = "Unresolvable artifact: [" + artifact + "]. (" +
destination + ")";
+ throw new ArtifactNotFoundException( error, artifact.toURI() );
+ }
+
+ /**
+ * Attempts to download and cache a remote artifact using a set of remote
+ * repositories.
+ * <p>
+ * This method allows an internal reference to be passed to the
+ * cache handler and it is expected to return the InputStream of the
+ * internal item inside Jar/Zip files. If this method is called, the
+ * implementation can assume that the artifact is a Zip file.
+ * </p>
+ *
+ * @param artifact the artifact to retrieve and cache
+ * @param resource referencing a item within the artifact. This
+ * argument may start with "!" or "!/", which should be ignored.
+ * @return a file referencing the local resource
+ * @exception IOException if an IO error occurs
+ * @exception TransitException is a transit system error occurs
+ */
+ public InputStream getResource( final Artifact artifact, final String
resource )
+ throws IOException, TransitException
+ {
+ String internalReference = resource;
+ synchronized( this )
+ {
+ if( internalReference.startsWith( "!" ) )
+ {
+ internalReference = internalReference.substring( 1 );
+ }
+ if( internalReference.startsWith( "/" ) )
+ {
+ internalReference = internalReference.substring( 1 );
+ }
+ ZipFile zip = m_zipCache.get( artifact );
+ if( zip == null )
+ {
+ File resourceFile = getResourceFile( artifact );
+ zip = new ZipFile( resourceFile );
+ m_zipCache.put( artifact, zip );
+ }
+ ZipEntry entry = zip.getEntry( internalReference );
+ InputStream stream = zip.getInputStream( entry );
+ return new BufferedInputStream( stream );
+ }
+ }
+
+ /**
+ * Creates an output stream to where the artifact content can be written
+ * to. If the artifact already exists and the artifact is not a link a
+ * <code>ArtifactAlreadyExistsException</code> will be thrown. If the
+ * directory doesn't exists, it will be created.
+ *
+ * @exception IOException if an IO error occurs.
+ * @exception NullPointerException if the artifact argument is null.
+ * @exception ArtifactAlreadyExistsException if the artifact already
exists
+ * in the cache and the artifact is not a link.
+ */
+ public OutputStream createOutputStream( Artifact artifact )
+ throws NullPointerException, ArtifactAlreadyExistsException,
IOException
+ {
+ if( null == artifact )
+ {
+ throw new NullPointerException( "artifact" );
+ }
+ Host any = findAnyPresence( artifact );
+ String scheme = artifact.getScheme();
+ boolean flag = !"link".equals( scheme );
+ if( ( any != null ) && flag )
+ {
+ throw new ArtifactAlreadyExistsException( "Artifact found on
server.", artifact );
+ }
+ String path = m_layout.resolvePath( artifact );
+ File destination = new File( m_cacheDir, path );
+ if( destination.exists() && flag )
+ {
+ throw new ArtifactAlreadyExistsException( "Artifact found in
cache.", artifact );
+ }
+ File parentDir = destination.getParentFile();
+ if( !parentDir.exists() )
+ {
+ parentDir.mkdirs();
+ }
+ return new FileOutputStream( destination );
+ }
+
+ /**
+ * Return the layout used by the cache.
+ * @return the cache layout
+ */
+ public Layout getLayout()
+ {
+ return m_layout;
+ }
+
+ //
------------------------------------------------------------------------
+ // implementation
+ //
------------------------------------------------------------------------
+
+ /**
+ * Return a resource host.
+ * @param artifact the artifact
+ * @return the resource host (possibly null)
+ */
+ private Host findKnownGroupHost( Artifact artifact )
+ {
+ synchronized( m_resourceHosts )
+ {
+ Iterator list = m_resourceHosts.iterator();
+ while ( list.hasNext() )
+ {
+ Host host = (Host) list.next();
+ if( host.isEnabled() )
+ {
+ if( host.checkPresence( artifact, true ) )
+ {
+ return host;
+ }
+ }
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Find any host.
+ * @param artifact the artifact
+ * @return the resource host (possibly null)
+ */
+ private Host findAnyPresence( Artifact artifact )
+ {
+ synchronized( m_resourceHosts )
+ {
+ //Iterator list = m_resourceHosts.values().iterator();
+ Iterator list = m_resourceHosts.iterator();
+ while ( list.hasNext() )
+ {
+ Host host = (Host) list.next();
+ if( host.isEnabled() )
+ {
+ if( host.checkPresence( artifact, false ) )
+ {
+ return host;
+ }
+ }
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Download an artifact from a host to the cache.
+ * @param host the remote host
+ * @param artifact the artifact being retrieved
+ * @param destination the cached destination
+ * @return TRUE if downloaded
+ * @exception IOException if an IO error occurs
+ * @exception TransitException if a transit system error occurs
+ */
+ private boolean download( Host host, Artifact artifact, File destination
)
+ throws IOException, TransitException
+ {
+ if( host == null )
+ {
+ return false;
+ }
+
+ File parentDir = destination.getParentFile();
+ File tempFile = File.createTempFile( "~dpml", ".tmp", parentDir );
+ tempFile.deleteOnExit(); // safety harness in case we abort
abnormally
+ FileOutputStream tempOut = new FileOutputStream( tempFile );
+
+ try
+ {
+ Date lastModified = host.download( artifact, tempOut );
+ // An atomic operation and no risk of a corrupted
+ // artifact content.
+ tempFile.renameTo( destination );
+ destination.setLastModified( lastModified.getTime() );
+ return true;
+ }
+ catch( Throwable e )
+ {
+ tempFile.delete();
+ getMonitor().failedDownloadFromHost( host.toString(), artifact,
e );
+ return false;
+ }
+ }
+
+ private Monitor getMonitor()
+ {
+ return m_context.getMonitor();
+ }
+
+ private void endNotifyMonitor(
+ boolean existed, Artifact artifact, File destination )
+ {
+ if( existed )
+ {
+ getMonitor().updatedLocalCache( artifact.toURL(), destination );
+ }
+ else
+ {
+ getMonitor().addedToLocalCache( artifact.toURL(), destination );
+ }
+ }
+
+ private void checkInternalConsistency( Artifact artifact, File
destination )
+ {
+ if( destination.exists() )
+ {
+ return;
+ }
+ final String error =
+ "Download reported [success], but the destination does not exist: "
+ + artifact
+ + ", "
+ + destination;
+ throw new InternalError( error );
+ }
+
+ /**
+ * Locates and if necessary downloads the artifact.
+ * @param artifact the Artifact to download and locate in the cache.
+ * @return the File pointing to the artifact. The file may not exist if
the
+ * download has failed.
+ */
+ private File getResourceFile( Artifact artifact )
+ throws TransitException, IOException
+ {
+ if( null == artifact )
+ {
+ throw new NullPointerException( "artifact" );
+ }
+ getMonitor().resourceRequested( artifact );
+
+ String path = m_layout.resolvePath( artifact );
+ File destination = new File( m_cacheDir, path );
+ File parentDir = destination.getParentFile();
+ parentDir.mkdirs();
+ boolean exist = destination.exists();
+ boolean success;
+ if( exist )
+ {
+ success = true;
+ }
+ else
+ {
+ Host known = findKnownGroupHost( artifact );
+ success = download( known, artifact, destination );
+ if( !success )
+ {
+ Host any = findAnyPresence( artifact );
+ success = download( any, artifact, destination );
+ }
+ }
+ if( success )
+ {
+ checkInternalConsistency( artifact, destination );
+ endNotifyMonitor( exist, artifact, destination );
+ }
+
+ if( !destination.exists() )
+ {
+ getMonitor().failedDownload( artifact );
+ }
+
+ return destination;
+ }
+
+ //
------------------------------------------------------------------------
+ // internals
+ //
------------------------------------------------------------------------
+
+ private Host createDefaultResourceHost( HostDirective directive ) throws
IOException
+ {
+ if( getLogger().isTraceEnabled() )
+ {
+ final String message =
+ "Creating host ["
+ + directive.getID()
+ + "] on "
+ + directive.getHost();
+ getLogger().trace( message );
+ }
+ try
+ {
+ Monitor monitor = getMonitor();
+ return new DefaultResourceHost( monitor, directive, m_logger );
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "Unexpected exception while attempting to load standard host:
" + directive.getID()
+ + "\nBase URL: " + directive.getHost();
+ throw new TransitException( error, e );
+ }
+ }
+
+ private Logger getLogger()
+ {
+ return m_logger;
+ }
+
+ private static HostDirective createLocalHostDirective( CacheDirective
directive )
+ {
+ String path = directive.getLocal();
+ String layout = directive.getLocalLayout();
+ return new HostDirective(
+ "local",
+ 10,
+ path,
+ null,
+ null,
+ null,
+ true,
+ true,
+ layout,
+ null,
+ null );
+ }
+
+}
+

Added: trunk/main/transit/core/src/main/dpml/transit/DefaultMonitor.java
===================================================================
--- trunk/main/transit/core/src/main/dpml/transit/DefaultMonitor.java
2007-02-08 23:39:34 UTC (rev 1832)
+++ trunk/main/transit/core/src/main/dpml/transit/DefaultMonitor.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2006-2007 Stephen McConnell
+ *
+ * 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 dpml.transit;
+
+import java.io.File;
+import java.net.URL;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import net.dpml.transit.Artifact;
+import net.dpml.transit.Monitor;
+
+/**
+ * The cache monitor router is responsible for the dispatiching of cache
monitor
+ * events to registered monitors.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+class DefaultMonitor implements Monitor, Iterable<Monitor>
+{
+ //--------------------------------------------------------------------
+ // state
+ //--------------------------------------------------------------------
+
+ /**
+ * List of attached monitors.
+ */
+ private final List<Monitor> m_monitors = new
CopyOnWriteArrayList<Monitor>();
+
+ //--------------------------------------------------------------------
+ // cache monitoring
+ //--------------------------------------------------------------------
+
+ /**
+ * Notify all monitors that a request for an artifact has been received.
+ * @param artifact the requested artifact
+ */
+ public void resourceRequested( Artifact artifact )
+ {
+ for( Monitor monitor : this )
+ {
+ monitor.resourceRequested( artifact );
+ }
+ }
+
+ /**
+ * Notify all monitors that a request artifact has been added to the
local cache.
+ * @param resource the url of the remote resource
+ * @param localFile the local file added to the cache
+ */
+ public void addedToLocalCache( URL resource, File localFile )
+ {
+ for( Monitor monitor : this )
+ {
+ monitor.addedToLocalCache( resource, localFile );
+ }
+ }
+
+ /**
+ * Notify all monitors that an artifact in the local cache has been
updated.
+ * @param resource the url of the remote resource
+ * @param localFile the local file that was modified
+ */
+ public void updatedLocalCache( URL resource, File localFile )
+ {
+ for( Monitor monitor : this )
+ {
+ monitor.updatedLocalCache( resource, localFile );
+ }
+ }
+
+ /**
+ * Notify all monitors that an artifact in the local cache was removed.
+ * @param resource the url of the remote resource
+ * @param localFile the local file that was removed
+ */
+ public void removedFromLocalCache( URL resource, File localFile )
+ {
+ for( Monitor monitor : this )
+ {
+ monitor.removedFromLocalCache( resource, localFile );
+ }
+ }
+
+ /**
+ * Notify all monitors that an artifact request on a named host failed.
+ * @param host the remote host
+ * @param artifact the requested artifact
+ * @param cause the cause of the failure
+ */
+ public void failedDownloadFromHost( String host, Artifact artifact,
Throwable cause )
+ {
+ for( Monitor monitor : this )
+ {
+ monitor.failedDownloadFromHost( host, artifact, cause );
+ }
+ }
+
+ /**
+ * Notify all monitors that an artifact request failed.
+ * @param artifact the requested artifact
+ */
+ public void failedDownload( Artifact artifact )
+ {
+ for( Monitor monitor : this )
+ {
+ monitor.failedDownload( artifact );
+ }
+ }
+
+ //--------------------------------------------------------------------
+ // network monitoring
+ //--------------------------------------------------------------------
+
+ /**
+ * Notify all subscribing monitors of a updated event.
+ * @param resource the url of the updated resource
+ * @param expected the size in bytes of the download
+ * @param count the progress in bytes
+ */
+ public void notifyUpdate( URL resource, int expected, int count )
+ {
+ for( Monitor monitor : this )
+ {
+ monitor.notifyUpdate( resource, expected, count );
+ }
+ }
+
+ /**
+ * Notify all subscribing monitors of a download completion event.
+ * @param resource the url of the downloaded resource
+ */
+ public void notifyCompletion( URL resource )
+ {
+ for( Monitor monitor : this )
+ {
+ monitor.notifyCompletion( resource );
+ }
+ }
+
+ //--------------------------------------------------------------------
+ // Router
+ //--------------------------------------------------------------------
+
+ /**
+ * Add a monitor to the set of monitors managed by this router.
+ * @param monitor the monitor to add
+ */
+ public void addMonitor( Monitor monitor )
+ {
+ m_monitors.add( monitor );
+ }
+
+ /**
+ * Remove a monitor from the set of monitors managed by this router.
+ * @param monitor the monitor to remove
+ */
+ public void removeMonitor( Monitor monitor )
+ {
+ m_monitors.remove( monitor );
+ }
+
+ public Iterator<Monitor> iterator()
+ {
+ return m_monitors.iterator();
+ }
+}
+

Added: trunk/main/transit/core/src/main/dpml/transit/DefaultResourceHost.java
===================================================================
--- trunk/main/transit/core/src/main/dpml/transit/DefaultResourceHost.java
2007-02-08 23:39:34 UTC (rev 1832)
+++ trunk/main/transit/core/src/main/dpml/transit/DefaultResourceHost.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,780 @@
+/*
+ * Copyright 2004 Niclas Hedhman.
+ * Copyright 2005-2007 Stephen J. McConnell.
+ *
+ * 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 dpml.transit;
+
+import dpml.util.PropertyResolver;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.UnknownHostException;
+import java.net.PasswordAuthentication;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Properties;
+
+import net.dpml.transit.Artifact;
+import net.dpml.transit.HostManager;
+import net.dpml.transit.Layout;
+import net.dpml.transit.TransitException;
+import net.dpml.transit.Transit;
+import net.dpml.transit.Monitor;
+
+import dpml.transit.info.HostDirective;
+
+import net.dpml.util.Logger;
+
+import static net.dpml.transit.Transit.DATA;
+
+/**
+ * Resource manager for a single host.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+class DefaultResourceHost implements Host, HostManager, Comparable<Host>
+{
+ //
------------------------------------------------------------------------
+ // state
+ //
------------------------------------------------------------------------
+
+ /**
+ * Known groups.
+ */
+ private HashSet<String> m_knownGroups = new HashSet<String>();
+
+ /**
+ * The key is the Artifact one wants to lock against, and the value is an
+ * anonymously lock object.
+ */
+ private HashMap<Artifact, Object> m_locks = new HashMap<Artifact,
Object>();
+
+ /**
+ * Connections.
+ */
+ private ConnectionCache m_connections;
+ private Layout m_layout;
+ private HostDirective m_directive;
+ private Logger m_logger;
+ private String m_path;
+ private URL m_base;
+ private PasswordAuthentication m_authentication;
+ private RequestIdentifier m_identifier;
+
+ private final Monitor m_monitor;
+
+ //
------------------------------------------------------------------------
+ // constructor
+ //
------------------------------------------------------------------------
+
+ /**
+ * Constructor for a resource host using a supplied host configuration.
+ *
+ * @param directive the immutable host configuration
+ * @param logger the assigned logging channel
+ * @exception UnknownHostException if the supplied base url references
an unknown host
+ */
+ DefaultResourceHost( Monitor monitor, HostDirective directive, Logger
logger )
+ throws UnknownHostException, IOException
+ {
+
+ m_logger = logger;
+ m_directive = directive;
+ m_monitor = monitor;
+
+ String layout = directive.getLayout();
+ m_layout = Layout.getLayout( layout );
+ m_connections = ConnectionCache.getInstance();
+
+ String username = directive.getUsername();
+ if( null != username )
+ {
+ char[] pswd = directive.getPassword();
+ m_authentication = new PasswordAuthentication( username, pswd );
+ }
+ else
+ {
+ m_authentication = new PasswordAuthentication( null, new char[0]
);
+ }
+
+ String id = directive.getID();
+ m_path = resolveBaseValue( directive.getHost() );
+ m_base = resolveBaseURL( id, m_path );
+
+ String scheme = directive.getScheme();
+ String prompt = directive.getPrompt();
+ m_identifier = getRequestIdentifier( m_base, scheme, prompt );
+
+ TransitAuthenticator ta = new TransitAuthenticatorImpl(
m_authentication );
+ DelegatingAuthenticator da = DelegatingAuthenticator.getInstance();
+ da.addTransitAuthenticator( ta, m_identifier );
+
+ String index = m_directive.getIndex();
+ setGroups( id, m_base, index );
+ }
+
+ //
------------------------------------------------------------------------
+ // Host
+ //
------------------------------------------------------------------------
+
+ /**
+ * Return the host base path.
+ * @return the base path
+ */
+ public String getBase()
+ {
+ return m_path;
+ }
+
+ /**
+ * Return the hostid.
+ * @return the host identifier
+ */
+ public String getID()
+ {
+ return m_directive.getID();
+ }
+
+ /**
+ * Return the host name.
+ * @return the hostname
+ */
+ public String getHostName()
+ {
+ return m_base.getHost();
+ }
+
+ /**
+ * Returns the full host url.
+ *
+ * @return the host url
+ */
+ public URL getURL()
+ {
+ return m_base;
+ }
+
+ /**
+ * Return the host priority.
+ * @return the priority
+ */
+ public int getPriority()
+ {
+ return m_directive.getPriority();
+ }
+
+ /**
+ * Downloads a given artifact.
+ * @param artifact the artifact that is requested to be downloaded.
+ * @param dest the destination output stream into which download content
is to be written
+ * @exception IOException if an IO related error occurs
+ */
+ public Date download( Artifact artifact, OutputStream dest )
+ throws IOException
+ {
+ Object lock = obtainLock( artifact );
+ synchronized ( lock )
+ {
+ NetworkLoader loader = new NetworkLoader( m_monitor );
+ URL url = createRemoteUrl( artifact );
+ URLConnection connection;
+ synchronized ( m_connections )
+ {
+ connection = m_connections.get( artifact );
+ if( connection == null )
+ {
+ Logger log = getLogger().getChildLogger( "log" );
+ if( log.isTraceEnabled() )
+ {
+ String message = this + " - Info: Connection no
longer in cache. Reconnecting.";
+ log.trace( message );
+ }
+ URL remote = createRemoteUrl( artifact );
+ connection = remote.openConnection();
+ connection.connect();
+ }
+ }
+ return loader.loadResource( url, connection, dest );
+ }
+ }
+
+ /**
+ * Uploads the given file to the resource host as an artifact.
+ *
+ * @param artifact the artifact destination specification.
+ * @param source The input stream from where to read the content to be
uploaded.
+ * @exception IOException if an IO related error occurs
+ */
+ public void upload( Artifact artifact, InputStream source )
+ throws IOException
+ {
+ // TODO: implement upload through HTTP POST requests.
+ }
+
+ /**
+ * Checks if the Artifact is present on the resource host.
+ *
+ * <p>
+ * Performs a check to see if the artifact exists on the resource host.
If
+ * <i>knownOnly</i> is set to true, then the implementation will only
+ * consult the knownGroups table, and if found there, it is considered
+ * found without checking at the resource host itself. If
<i>knownOnly</i>
+ * is false, however, a connection will be established to the resource
+ * host and a check of the actual resource existence.
+ * </p>
+ *
+ * @param artifact the artifact for which the method checks its presence.
+ * @param knownOnly does not perform a remote connection, and instead
lookup
+ * the group table, and if not found there it will return false.
+ *
+ * @return true if the artifact can be located, false otherwise.
+ */
+ public boolean checkPresence( Artifact artifact, boolean knownOnly )
+ {
+ if( "file".equals( getURL().getProtocol() ) )
+ {
+ return checkAtServer( artifact );
+ }
+ else if( knownOnly )
+ {
+ return checkKnown( artifact );
+ }
+ else
+ {
+ return checkAtServer( artifact );
+ }
+ }
+
+ /**
+ * Return true if the reosurce host is enabled and online.
+ *
+ * @return true if the reosurce host is enabled and online.
+ */
+ public boolean isEnabled()
+ {
+ return m_directive.getEnabled();
+ }
+
+ /** Returns true if the Host is considered trusted.
+ *
+ * @return true if the Host is considered trusted.
+ */
+ public boolean isTrusted()
+ {
+ return m_directive.getTrusted();
+ }
+
+ /**
+ * Returns the layout assigned to the host.
+ *
+ * @return the layout strategy
+ */
+ public Layout getLayout()
+ {
+ return m_layout;
+ }
+
+ /**
+ * Returns the layout id assigned to the host.
+ *
+ * @return the layout strategy id
+ */
+ public String getLayoutID()
+ {
+ return m_layout.getID();
+ }
+
+ //
------------------------------------------------------------------------
+ // implementation
+ //
------------------------------------------------------------------------
+
+ private void setGroups( String id, URL base, String path ) throws
IOException
+ {
+ URL index = resolveIndexURL( id, base, path );
+ if( null != index )
+ {
+ String[] groups = getKnownGroups( index );
+ setGroups( groups );
+ }
+ else
+ {
+ setGroups( new String[0] );
+ }
+ }
+
+ private void setGroups( String[] groups )
+ {
+ synchronized( m_knownGroups )
+ {
+ m_knownGroups.clear();
+ for( int i=0; i < groups.length; i++ )
+ {
+ String group = groups[i];
+ m_knownGroups.add( group );
+ }
+ }
+ }
+
+ /**
+ * Check if the supplied artifact group is known.
+ * @param artifact the subject artifact to check
+ * @return TRUE if known else FALSE
+ */
+ private boolean checkKnown( Artifact artifact )
+ {
+ String group = artifact.getGroup();
+ return m_knownGroups.contains( group );
+ }
+
+ /**
+ * Ckeck if the server conection is available.
+ * @param artifact the subject artifact
+ * @return TRUE if a connection is available
+ */
+ private boolean checkAtServer( Artifact artifact )
+ {
+ try
+ {
+ URL remote = createRemoteUrl( artifact );
+ String protocol = remote.getProtocol();
+ if( protocol.startsWith( "file" ) )
+ {
+ String path = remote.getPath();
+ File f = new File( path );
+ return f.exists();
+ }
+ else
+ {
+ return openRemoteConnection( artifact );
+ }
+ }
+ catch( IOException e )
+ {
+ return false;
+ }
+ catch( NoSuchAlgorithmException e )
+ {
+ return false;
+ }
+ catch( KeyManagementException e )
+ {
+ return false;
+ }
+ catch( RuntimeException e )
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Obtain a lock on the supplied artifact.
+ * @param artifact the artifact to obtain a lock on
+ * @return the lock
+ */
+ private Object obtainLock( Artifact artifact )
+ {
+ synchronized ( this )
+ {
+ Object lock = m_locks.get( artifact );
+ if( lock == null )
+ {
+ lock = new Object();
+ m_locks.put( artifact, lock );
+ }
+ return lock;
+ }
+ }
+
+ /**
+ * Open a remote connection relative to a supplied artifact.
+ * @param artifact the artifact against which a connection will be
established
+ * @exception IOException if an IO error occurs
+ * @exception KeyManagementException if a key management error occurs
+ * @exception NoSuchAlgorithmException if no such algorithm exists?
+ * @return true if the atrifact was found and could be opened, false if
not
+ * available at this resource host.
+ */
+ private boolean openRemoteConnection( Artifact artifact )
+ throws IOException, KeyManagementException, NoSuchAlgorithmException
+ {
+ Logger log = getLogger().getChildLogger( "log" );
+ if( log.isTraceEnabled() )
+ {
+ String message = this + " - opening connection: " + artifact;
+ log.trace( message );
+ }
+ URL remote = createRemoteUrl( artifact );
+ URLConnection conn = remote.openConnection();
+ if( conn instanceof HttpsURLConnection )
+ {
+ if( log.isTraceEnabled() )
+ {
+ String message = this + " - HTTPS connection opened.";
+ log.trace( message );
+ }
+ if( isTrusted() )
+ {
+ if( log.isTraceEnabled() )
+ {
+ String message = this + " - Using NullTrustManager.";
+ log.trace( message );
+ }
+ HttpsURLConnection ssl = (HttpsURLConnection) conn;
+ TrustManager nullTrustManager = new NullTrustManager();
+ SSLContext ctx = SSLContext.getInstance( "SSLv3" );
+ ctx.init( null, new TrustManager[]{nullTrustManager}, null );
+ if( log.isTraceEnabled() )
+ {
+ String message = this + " - Setting SSLv3 socket
factory.";
+ log.trace( message );
+ }
+ SSLSocketFactory factory = ctx.getSocketFactory();
+ ssl.setSSLSocketFactory( factory );
+ }
+ }
+ conn.connect();
+ if( conn instanceof HttpURLConnection )
+ {
+ int code = ( (HttpURLConnection) conn ).getResponseCode();
+ if( log.isTraceEnabled() )
+ {
+ String message = this + " - ResponseCode: " + code;
+ log.trace( message );
+ }
+ if( code == HttpURLConnection.HTTP_UNAUTHORIZED )
+ {
+ throw new IOException( "Unauthorized request." );
+ }
+ else if( code == HttpURLConnection.HTTP_NOT_FOUND )
+ {
+ return false;
+ }
+ else if( code != HttpURLConnection.HTTP_OK )
+ {
+ throw new IOException( "Unexpected Result: " + code );
+ }
+ }
+ synchronized ( m_connections )
+ {
+ if( log.isTraceEnabled() )
+ {
+ String message = this + " - caching connection: " + conn;
+ log.trace( message );
+ }
+ m_connections.put( artifact, conn );
+ }
+ return true;
+ }
+
+ /**
+ * Create a remote url from an artifact.
+ *
+ * @param artifact the subject artifact
+ * @return the remote url connection
+ * @exception MalformedURLException if the artifact path is not
resolvable to a url
+ */
+ private URL createRemoteUrl( Artifact artifact )
+ throws MalformedURLException
+ {
+ String path = m_layout.resolvePath( artifact );
+ URL base = getURL();
+ URL url = new URL( base, path );
+ return url;
+ }
+
+ /**
+ * Return a string representation of this host.
+ * @return the representation
+ */
+ public String toString()
+ {
+ return "[HOST: " + getURL() + "]";
+ }
+
+ private Logger getLogger()
+ {
+ return m_logger;
+ }
+
+ /**
+ * Compare this host with another. Lower priorities rank higherest.
+ * @param host the other host
+ * @return the relative ranking of the other host
+ */
+ public int compareTo( Host host )
+ {
+ int primaryPriority = getPriority();
+ int secondaryPrimary = host.getPriority();
+ if( primaryPriority < secondaryPrimary )
+ {
+ return -1;
+ }
+ else if( primaryPriority == secondaryPrimary )
+ {
+ return 0;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+
+ //
------------------------------------------------------------------------
+ // static (utils)
+ //
------------------------------------------------------------------------
+
+ private static RequestIdentifier getRequestIdentifier( URL base, String
scheme, String prompt )
+ {
+ if( null == base )
+ {
+ throw new NullPointerException( "base" );
+ }
+ if( null == scheme )
+ {
+ throw new NullPointerException( "scheme" );
+ }
+ if( null == prompt )
+ {
+ throw new NullPointerException( "prompt" );
+ }
+ String protocol = base.getProtocol();
+ String host = base.getHost();
+ int port = base.getPort();
+ if( port == 0 )
+ {
+ if( protocol.equals( "http" ) )
+ {
+ port = HTTP_PORT;
+ }
+ else if( protocol.equals( "ftp" ) )
+ {
+ port = FTP_PORT;
+ }
+ else if( protocol.equals( "https" ) )
+ {
+ port = HTTPS_PORT;
+ }
+ }
+ return new RequestIdentifier( host, port, protocol, scheme, prompt );
+ }
+
+ /**
+ * A null trust manager that will accept any certificate. I.e. this
+ * class performs NO TRUST MANAGEMENT and simply serves as a mechanism
+ * through which https connections can be established with the same notion
+ * of trust as a http connection (i.e. none).
+ */
+ private static final class NullTrustManager
+ implements X509TrustManager
+ {
+ /**
+ * Empty certificate sequence.
+ */
+ private static final X509Certificate[] EMPTY_CERTS = new
X509Certificate[0];
+
+ /**
+ * Null implementation.
+ * @param certs the supplied certs (ignored)
+ * @param authType the supplied type (ignored)
+ */
+ public void checkServerTrusted( final X509Certificate[] certs, final
String authType )
+ {
+ //PrintWriter log = Transit.getInstance().getLogWriter();
+ //log.println( "NullTrustManager: authType=" + authType );
+ //log.println( "Server Certificates" );
+ //log.println( "-------------------" );
+ //for( int i=0; i < certs.length; i++ )
+ //{
+ // log.println( " " + certs[ i ] );
+ //}
+ }
+
+ /**
+ * Null implementation.
+ * @param certs the supplied certs (ignored)
+ * @param authType the supplied type (ignored)
+ */
+ public void checkClientTrusted( final X509Certificate[] certs, final
String authType )
+ {
+ //PrintWriter log = Transit.getInstance().getLogWriter();
+ //log.println( "NullTrustManager: authType=" + authType );
+ //log.println( "Client Certificates" );
+ //log.println( "-------------------" );
+ //for( int i=0; i < certs.length; i++ )
+ //{
+ // log.println( " " + certs[ i ] );
+ //}
+ }
+
+ /**
+ * Null implementation.
+ * @return an empty certificate array
+ */
+ public X509Certificate[] getAcceptedIssuers()
+ {
+ return EMPTY_CERTS;
+ }
+ }
+
+ /**
+ * Return a set of known groups froma host.
+ * @param href the host against which the request is to be made
+ * @return the set of known group names
+ * @exception TransitException if an error occurs while attempting to
read the
+ * remote address
+ */
+ private static String[] getKnownGroups( URL href ) throws
TransitException
+ {
+ if( href != null )
+ {
+ try
+ {
+ return PropertyUtils.readListFile( href );
+ }
+ catch( Exception e )
+ {
+ final String error =
+ "Unable to extract the groups from "
+ + href;
+ throw new TransitException( error, e );
+ }
+ }
+ else
+ {
+ return new String[0];
+ }
+ }
+
+ private static String resolveBaseValue( String path )
+ {
+ //
+ // make sure the base path ends with a "/" otherwise relative url
references
+ // will not be correct
+ //
+
+ if( !path.endsWith( "/" ) )
+ {
+ return path + "/";
+ }
+ else
+ {
+ return path;
+ }
+ }
+
+ private static URL resolveBaseURL( String id, String path ) throws
MalformedURLException
+ {
+ if( null == path )
+ {
+ return getDefaultHostURL();
+ }
+ try
+ {
+ Properties properties = System.getProperties();
+ String spec = PropertyResolver.resolve( properties, path );
+ return new URL( spec );
+ }
+ catch( MalformedURLException e )
+ {
+ final String error =
+ "Invalid host base url"
+ + "\nHost ID: " + id
+ + "\nHost Path: " + path
+ + "\nCause: " + e.getMessage();
+ throw new MalformedURLException( error );
+ }
+ }
+
+ private static URL resolveIndexURL( String id, URL base, String path )
throws MalformedURLException
+ {
+ if( null == path )
+ {
+ return null;
+ }
+
+ Properties properties = System.getProperties();
+ String resolved = PropertyResolver.resolve( properties, path );
+
+ try
+ {
+ return new URL( resolved );
+ }
+ catch( MalformedURLException e )
+ {
+ try
+ {
+ return new URL( base, resolved );
+ }
+ catch( MalformedURLException ee )
+ {
+ final String error =
+ "Invalid index url"
+ + "\nHost ID: " + id
+ + "\nHost Path: " + base
+ + "\nIndex Path: " + path
+ + "\nCause: " + e.getMessage();
+ throw new MalformedURLException( error );
+ }
+ }
+ }
+
+ private static URL getDefaultHostURL()
+ {
+ try
+ {
+ return new URL( "http://localhost"; );
+ }
+ catch( Exception e )
+ {
+ return null;
+ }
+ }
+
+ /**
+ * HTTP port number.
+ */
+ private static final int HTTP_PORT = 80;
+
+ /**
+ * FTP port number.
+ */
+ private static final int FTP_PORT = 21;
+
+ /**
+ * HTTPS port number.
+ */
+ private static final int HTTPS_PORT = 443;
+
+}

Added:
trunk/main/transit/core/src/main/dpml/transit/DelegatingAuthenticator.java
===================================================================
---
trunk/main/transit/core/src/main/dpml/transit/DelegatingAuthenticator.java
2007-02-08 23:39:34 UTC (rev 1832)
+++
trunk/main/transit/core/src/main/dpml/transit/DelegatingAuthenticator.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2004 Niclas Hedhman, DPML
+ * Copyright 2005-2007 Stephen J. McConnell.
+ *
+ * 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 dpml.transit;
+
+import java.io.PrintWriter;
+import java.net.Authenticator;
+import java.net.PasswordAuthentication;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import net.dpml.transit.Transit;
+
+/**
+ * Internal class used to handle delegated authentication.
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+final class DelegatingAuthenticator extends Authenticator
+{
+ //
------------------------------------------------------------------------
+ // static
+ //
------------------------------------------------------------------------
+
+ /**
+ * The singleton delegating authenticator instance.
+ */
+ private static DelegatingAuthenticator m_INSTANCE;
+
+ //
------------------------------------------------------------------------
+ // state
+ //
------------------------------------------------------------------------
+
+ /**
+ * The set of registered authenticators keyed by id.
+ */
+ private Map<RequestIdentifier, TransitAuthenticator> m_authenticators;
+
+ /**
+ * Return the singleton authenticator.
+ * @return the authenticator
+ */
+ public static DelegatingAuthenticator getInstance()
+ {
+ synchronized( DelegatingAuthenticator.class )
+ {
+ if( m_INSTANCE == null )
+ {
+ m_INSTANCE = new DelegatingAuthenticator();
+ Authenticator.setDefault( m_INSTANCE );
+ }
+ return m_INSTANCE;
+ }
+ }
+
+ //
------------------------------------------------------------------------
+ // constructor
+ //
------------------------------------------------------------------------
+
+ /**
+ * Creation of a new delegating authenticator.
+ */
+ private DelegatingAuthenticator()
+ {
+ m_authenticators = new HashMap<RequestIdentifier,
TransitAuthenticator>();
+ }
+
+ //
------------------------------------------------------------------------
+ // implementation
+ //
------------------------------------------------------------------------
+
+ /**
+ * Add an authenticator to the set of authenticators managed by the
+ * singleton delegating authenticator.
+ * @param authenticator the authenticator to add
+ * @param id the request identifier
+ */
+ public void addTransitAuthenticator( TransitAuthenticator authenticator,
RequestIdentifier id )
+ {
+ synchronized( m_authenticators )
+ {
+ m_authenticators.put( id, authenticator );
+ }
+ }
+
+ /**
+ * Remove an authenticator from the set of authenticators managed by the
+ * singleton delegating authenticator.
+ * @param authenticator the authenticator to remove
+ */
+ public void removeTransitAuthenticator( TransitAuthenticator
authenticator )
+ {
+ synchronized( m_authenticators )
+ {
+ Iterator list = m_authenticators.values().iterator();
+ while( list.hasNext() )
+ {
+ Authenticator item = (Authenticator) list.next();
+ if( item.equals( authenticator ) )
+ {
+ list.remove();
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the password authenticator.
+ * @return the password authenticator
+ */
+ protected PasswordAuthentication getPasswordAuthentication()
+ {
+ String host = getRequestingHost();
+ String protocol = getRequestingProtocol();
+ String prompt = getRequestingPrompt();
+ String scheme = getRequestingScheme();
+ int port = getRequestingPort();
+ if( host == null )
+ {
+ host = getRequestingSite().getHostName();
+ if( host == null || "".equals( host ) )
+ {
+ host = getRequestingSite().getHostAddress();
+ }
+ }
+
+ RequestIdentifier id = new RequestIdentifier( host, port, protocol,
scheme, prompt );
+
+ //try
+ //{
+ // PrintWriter log = Transit.getInstance().getLogWriter();
+ // log.println( "Authentication Required: " + id );
+ // log.println( "Authenticators Available: " + m_authenticators );
+ //}
+ //catch( Exception e )
+ //{
+ // boolean ignorable = true;
+ //}
+
+ synchronized( m_authenticators )
+ {
+ TransitAuthenticator auth = (TransitAuthenticator)
m_authenticators.get( id );
+ if( auth == null )
+ {
+ return null;
+ }
+ return auth.resolvePasswordAuthentication( this );
+ }
+ }
+}

Added: trunk/main/transit/core/src/main/dpml/transit/Host.java
===================================================================
--- trunk/main/transit/core/src/main/dpml/transit/Host.java 2007-02-08
23:39:34 UTC (rev 1832)
+++ trunk/main/transit/core/src/main/dpml/transit/Host.java 2007-02-08
23:42:59 UTC (rev 1833)
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2004 Niclas Hedhman.
+ * Copyright 2005-2007 Stephen McConnell
+ *
+ * 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 dpml.transit;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Date;
+
+import net.dpml.transit.Artifact;
+
+/**
+ * Resource host SPI for protocol handlers.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public interface Host
+{
+ /**
+ * Downloads the given artifact to the directory indicated. The
+ * cachedir argument is the root cache directory, and the
+ * ResourceHost class is responsible for the creation of the
+ * directory structure of the group if nonexistent. If the
+ * knownOnly argument is true, then only attempt download if
+ * the group is known to exist on this resource host.
+ *
+ * @param artifact the artifact that is requested to be downloaded
+ * @param dest The output stream where to write the downloaded content
+ * @return the lastModified date of the downloaded artifact
+ * @exception IOException if an IO related error occurs
+ */
+ Date download( Artifact artifact, OutputStream dest )
+ throws IOException;
+
+ /**
+ * Uploads the given file to the resource host as an artifact.
+ *
+ * @param artifact the artifact destination specification
+ * @param source The input stream from where to read content
+ * @exception IOException if an IO related error occurs
+ */
+ void upload( Artifact artifact, InputStream source )
+ throws IOException;
+
+ /**
+ * Checks if the Artifact is present on the resource host.
+ *
+ * Performs a check to see if the artifact exists on the resource host. If
+ * <i>knownOnly</i> is set to true, then the implementation will only
+ * consult the knownGroups table, and if found there, it is considered
+ * found without checking at the resource host itself. If <i>knownOnly</i>
+ * is false, however, a connection will be established to the resource
+ * host and a check of the actual resource existence.
+ *
+ * @param artifact the target artifact
+ * @param knownOnly does not perform a remote connection, and instead
lookup
+ * the group table, and if not found there it will return false
+ * @return true if the artifact can be located, false otherwise.
+ */
+ boolean checkPresence( Artifact artifact, boolean knownOnly );
+
+ /**
+ * Returns the hostname of the resource host.
+ *
+ * This does not include any of the path, but does include any port number
+ * of this resource host.
+ *
+ * @return the hostname
+ */
+ String getHostName();
+
+ /**
+ * Returns the full host url.
+ *
+ * @return the host url
+ */
+ URL getURL();
+
+ /**
+ * Return true if the resource host has been enabled.
+ *
+ * @return true if the resource host is enabled, false if not.
+ */
+ boolean isEnabled();
+
+ /**
+ * Returns true if the ResourceHost is considered trusted.
+ * @return true if the host is trusted
+ */
+ boolean isTrusted();
+
+ /**
+ * Returns the priority of the resource host.
+ *
+ * A high number indicates a more important host that should take
precendence
+ * over a host with lower number.
+ * @return the host priority
+ */
+ int getPriority();
+}

Added: trunk/main/transit/core/src/main/dpml/transit/NetworkLoader.java
===================================================================
--- trunk/main/transit/core/src/main/dpml/transit/NetworkLoader.java
2007-02-08 23:39:34 UTC (rev 1832)
+++ trunk/main/transit/core/src/main/dpml/transit/NetworkLoader.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2004-2007 Stephen J. McConnell.
+ * Copyright 2004 Niclas Hedhman
+ * 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 dpml.transit;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Date;
+
+import net.dpml.transit.ArtifactException;
+import net.dpml.transit.Monitor;
+import net.dpml.transit.TransitException;
+import net.dpml.transit.Transit;
+
+/**
+ * Nework loader utility.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+class NetworkLoader
+{
+ /**
+ * Network monitor router.
+ */
+ private Monitor m_monitor;
+
+ /**
+ * Creation of a new network loader.
+ * @exception TransitException if an error in transit system
establishment occurs
+ */
+ public NetworkLoader( Monitor monitor )
+ throws TransitException
+ {
+ m_monitor = monitor;
+ }
+
+ //
------------------------------------------------------------------------
+ // implementation
+ //
------------------------------------------------------------------------
+
+ /**
+ * Retrieve a remote resource.
+ *
+ * @param url the of the file to retrieve
+ * @param connection the url connection
+ * @param destination where to store it
+ * @return the lastModified date of the downloaded artifact.
+ * @exception net.dpml.transit.ArtifactException if an artifact related
errror occurs
+ * @exception IOException if an IO error occurs
+ */
+ public Date loadResource( URL url, URLConnection connection,
OutputStream destination )
+ throws ArtifactException, IOException
+ {
+ if( connection instanceof HttpURLConnection )
+ {
+ HttpURLConnection httpConnection = (HttpURLConnection)
connection;
+ int code = httpConnection.getResponseCode();
+ // test for 401 result (HTTP only)
+ if ( code == HttpURLConnection.HTTP_UNAUTHORIZED )
+ {
+ throw new IOException( "Not authorized." );
+ }
+ }
+
+ InputStream in = connection.getInputStream();
+ int expected = connection.getContentLength();
+ StreamUtils.copyStream( m_monitor, url, expected, in, destination,
true );
+ long remoteTimestamp = connection.getLastModified();
+ return new Date( remoteTimestamp );
+ }
+}

Added: trunk/main/transit/core/src/main/dpml/transit/PropertyUtils.java
===================================================================
--- trunk/main/transit/core/src/main/dpml/transit/PropertyUtils.java
2007-02-08 23:39:34 UTC (rev 1832)
+++ trunk/main/transit/core/src/main/dpml/transit/PropertyUtils.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2004 Niclas Hedhman
+ * Copyright 2007 Stephen J. McConnell.
+ *
+ * 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 dpml.transit;
+
+import java.util.Properties;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.ArrayList;
+import java.net.URL;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.BufferedReader;
+
+import dpml.util.PropertyResolver;
+
+import net.dpml.transit.Transit;
+
+
+/**
+ * Utility class supporting operations related to property retrival.
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+final class PropertyUtils
+{
+ //
------------------------------------------------------------------------
+ // static
+ //
------------------------------------------------------------------------
+
+ /**
+ * Read a set of properties from a property file specificed by a url.
+ * Property files may reference symbolic properties in the form ${name}.
+ * @param propsUrl the url of the property file to read
+ * @return the resolved properties
+ * @exception IOException if an io error occurs
+ */
+ public static Properties readProps( URL propsUrl )
+ throws IOException
+ {
+ return readProps( propsUrl, true );
+ }
+
+ /**
+ * Read a set of properties from a property file specificed by a url.
+ * Property files may reference symbolic properties in the form ${name}.
+ * @param propsUrl the url of the property file to read
+ * @param resolve if TRUE apply property symbol resolution
+ * @return the resolved properties
+ * @exception IOException if an io error occurs
+ */
+ @SuppressWarnings( "unchecked" )
+ public static Properties readProps( URL propsUrl, boolean resolve )
+ throws IOException
+ {
+ InputStream stream = propsUrl.openStream();
+ try
+ {
+ Properties p = new Properties();
+ p.load( stream );
+ if( resolve )
+ {
+ p.setProperty( "dpml.home", Transit.HOME.toString() );
+ Iterator list = p.entrySet().iterator();
+ while ( list.hasNext() )
+ {
+ Map.Entry entry = (Map.Entry) list.next();
+ String value = (String) entry.getValue();
+ value = resolveProperty( p, value );
+ entry.setValue( value );
+ }
+ }
+ return p;
+ }
+ finally
+ {
+ stream.close();
+ }
+ }
+
+ /**
+ * Resolve symbols in a supplied value against supplied known properties.
+ * @param props a set of know properties
+ * @param value the string to parse for tokens
+ * @return the resolved string
+ */
+ public static String resolveProperty( Properties props, String value )
+ {
+ value = PropertyResolver.resolve( props, value );
+ return value;
+ }
+
+ /**
+ * Return the value of a property.
+ * @param props the property file
+ * @param key the property key to lookup
+ * @param def the default value
+ * @return the resolve value
+ */
+ public static String getProperty( Properties props, String key, String
def )
+ {
+ String value = props.getProperty( key, def );
+ if( value == null )
+ {
+ return null;
+ }
+ if( "".equals( value ) )
+ {
+ return value;
+ }
+ value = PropertyResolver.resolve( props, value );
+ return value;
+ }
+
+ /**
+ * Read a file and return the list of lines in an array of strings.
+ * @param listFile the url to read from
+ * @return the lines
+ * @exception IOException if a read error occurs
+ */
+ public static String[] readListFile( URL listFile )
+ throws IOException
+ {
+ ArrayList<String> list = new ArrayList<String>();
+ InputStream stream = openInputStream( listFile );
+ try
+ {
+ InputStreamReader isr = new InputStreamReader( stream, "UTF-8" );
+ BufferedReader reader = new BufferedReader( isr );
+ String line = reader.readLine();
+ while ( line != null )
+ {
+ list.add( line );
+ line = reader.readLine();
+ }
+ String[] items = new String[ list.size() ];
+ list.toArray( items );
+ return items;
+ }
+ finally
+ {
+ stream.close();
+ }
+ }
+
+ private static InputStream openInputStream( URL url ) throws IOException
+ {
+ try
+ {
+ return url.openStream();
+ }
+ catch( IOException e )
+ {
+ System.out.println( "#URL: " + url );
+ System.out.println( e.toString() );
+ throw e;
+ }
+ }
+
+ //
------------------------------------------------------------------------
+ // constructor
+ //
------------------------------------------------------------------------
+
+ /**
+ * Constructor.
+ */
+ private PropertyUtils()
+ {
+ }
+}

Added: trunk/main/transit/core/src/main/dpml/transit/RequestIdentifier.java
===================================================================
--- trunk/main/transit/core/src/main/dpml/transit/RequestIdentifier.java
2007-02-08 23:39:34 UTC (rev 1832)
+++ trunk/main/transit/core/src/main/dpml/transit/RequestIdentifier.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2006-2007 Stephen McConnell.
+ *
+ * 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 dpml.transit;
+
+import java.io.Serializable;
+
+/**
+ * A request identifier.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+final class RequestIdentifier implements Serializable
+{
+ //
------------------------------------------------------------------------
+ // static
+ //
------------------------------------------------------------------------
+
+ /**
+ * Serial version identifier.
+ */
+ static final long serialVersionUID = 1L;
+
+ /**
+ * Used in hashcode calculation.
+ */
+ private static final int MAGIC_NUMBER = 72349724;
+
+ //
------------------------------------------------------------------------
+ // state
+ //
------------------------------------------------------------------------
+
+ /**
+ * The internet address.
+ */
+ private final String m_address;
+
+ /**
+ * The port.
+ */
+ private final int m_port;
+
+ /**
+ * The prompt.
+ */
+ private final String m_prompt;
+
+ /**
+ * The protocol.
+ */
+ private final String m_protocol;
+
+ /**
+ * The scheme.
+ */
+ private final String m_scheme;
+
+ //
------------------------------------------------------------------------
+ // constructor
+ //
------------------------------------------------------------------------
+
+ /**
+ * Creation of a new request identifier.
+ * @param address the address
+ * @param port the port
+ * @param protocol the protocol
+ * @param scheme the scheme
+ * @param prompt the prompt
+ * @exception NullPointerException if any argument is null
+ */
+ public RequestIdentifier(
+ String address, int port, String protocol, String scheme, String
prompt )
+ throws NullPointerException
+ {
+ if( address == null )
+ {
+ throw new NullPointerException( "address" );
+ }
+ if( protocol == null )
+ {
+ throw new NullPointerException( "protocol" );
+ }
+ if( scheme == null )
+ {
+ throw new NullPointerException( "scheme" );
+ }
+ if( prompt == null )
+ {
+ throw new NullPointerException( "prompt" );
+ }
+ m_address = address;
+ m_port = port;
+ m_protocol = protocol;
+ m_prompt = prompt;
+ m_scheme = scheme;
+ }
+
+ //
------------------------------------------------------------------------
+ // implementation
+ //
------------------------------------------------------------------------
+
+ /**
+ * Test for equality.
+ *
+ * @param obj the object to test against
+ * @return true if this object is the same as the supplied object
+ */
+ public boolean equals( Object obj )
+ {
+ if( !( obj instanceof RequestIdentifier ) )
+ {
+ return false;
+ }
+ RequestIdentifier other = (RequestIdentifier) obj;
+ if( m_port != other.m_port )
+ {
+ return false;
+ }
+ if( !m_address.equals( other.m_address ) )
+ {
+ return false;
+ }
+ if( !m_protocol.equals( other.m_protocol ) )
+ {
+ return false;
+ }
+ if( !m_prompt.equals( other.m_prompt ) )
+ {
+ return false;
+ }
+ if( !m_scheme.equals( other.m_scheme ) )
+ {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Return the hascode for this instance.
+ * @return the hashcode
+ */
+ public int hashCode()
+ {
+ int hash = MAGIC_NUMBER * m_port;
+ hash = hash ^ m_address.hashCode();
+ hash = hash ^ m_protocol.hashCode();
+ hash = hash ^ m_prompt.hashCode();
+ hash = hash ^ m_scheme.hashCode();
+ return hash;
+ }
+
+ /**
+ * Return the string representation of this instance.
+ * @return the string value
+ */
+ public String toString()
+ {
+ StringBuffer b = new StringBuffer();
+ b.append( "ID[ " );
+ b.append( m_protocol );
+ b.append( ", " );
+ b.append( m_address );
+ b.append( ", " );
+ b.append( m_port );
+ b.append( ", " );
+ b.append( m_scheme );
+ b.append( ", " );
+ b.append( m_prompt );
+ b.append( " ]" );
+ return b.toString();
+ }
+}
+

Added: trunk/main/transit/core/src/main/dpml/transit/StandardLinkManager.java
===================================================================
--- trunk/main/transit/core/src/main/dpml/transit/StandardLinkManager.java
2007-02-08 23:39:34 UTC (rev 1832)
+++ trunk/main/transit/core/src/main/dpml/transit/StandardLinkManager.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,254 @@
+/*
+ * Copyright 2005-2007 Stephen J. McConnell.
+ *
+ * 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 dpml.transit;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.Properties;
+
+import net.dpml.transit.Artifact;
+import net.dpml.transit.ArtifactNotFoundException;
+import net.dpml.transit.TransitRuntimeException;
+import net.dpml.transit.LinkManager;
+import net.dpml.transit.LinkNotFoundException;
+
+import dpml.util.PropertyResolver;
+
+/**
+ * A link manager that maintains persistent link information as a resource.
+ * Link resource located using the
[cache]/[group]/[name]/[type]s/[name]-[version].[type].link
+ * resource naming convention.
+ *
+ * Applications should not call the methods for the LinkManager directly,
+ * and it is likely that the LinkManager remains outside the reachability of
+ * applications.
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+class StandardLinkManager
+ implements LinkManager
+{
+ /**
+ * Sets the URI for the provided Link.
+ * The LinkManager is required to persist this information between
+ * JVM restarts and should be persisted on a scope larger than a
+ * single JVM, typically a host or a local area network. LinkManagers
+ * are encouraged to establish other virtual scopes independent of
+ * network topologies.
+ *
+ * @param linkUri the uri of the link resource
+ * @param targetUri the uri that the link redirects to
+ * @exception IOException if the mapping could not be updated.
+ * @exception NullPointerException if the linkUri argument is null.
+ */
+ public void setTargetURI( final URI linkUri, final URI targetUri )
+ throws IOException, NullPointerException
+ {
+ if( null == linkUri )
+ {
+ throw new NullPointerException( "linkUri" );
+ }
+
+ try
+ {
+ AccessController.doPrivileged(
+ new PrivilegedExceptionAction<Object>()
+ {
+ public Object run()
+ throws IOException
+ {
+ String artifact = linkUri.toASCIIString();
+ URL store = new URL( null, artifact, new
dpml.transit.artifact.Handler() );
+ OutputStream out =
store.openConnection().getOutputStream();
+ byte[] array = getByteArray( targetUri );
+ ByteArrayInputStream in = new ByteArrayInputStream(
array );
+ StreamUtils.copyStream( in, out, true );
+ return null;
+ }
+ }
+ );
+ }
+ catch( PrivilegedActionException e )
+ {
+ throw (IOException) e.getException();
+ }
+ }
+
+ /**
+ * Returns the URI that the provided link URI instance is pointing to.
+ * @param linkUri the link uri from which the target will be resolved
+ * @exception LinkNotFoundException if the supplied link uri could not
be located
+ * @exception IOException if the mapping could not be retrieved, due to
+ * an IOException during link retrival.
+ * @return target URI that the link points to (possibly null if the link
does
+ * not declare a target)
+ */
+ public URI getTargetURI( final URI linkUri )
+ throws IOException, LinkNotFoundException
+ {
+ URIHolder holder = new URIHolder( linkUri );
+ final URI uri = holder.getBaseURI();
+ final String query = holder.getQuery();
+
+ try
+ {
+ URI result = (URI) AccessController.doPrivileged(
+ new PrivilegedExceptionAction<Object>()
+ {
+ public Object run()
+ throws IOException
+ {
+ URL store = null;
+ if( Artifact.isRecognized( uri ) )
+ {
+ String artifact = uri.toASCIIString();
+ store = new URL( null, artifact, new
dpml.transit.artifact.Handler() );
+ }
+ else
+ {
+ store = uri.toURL();
+ }
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ InputStream in = store.openConnection().getInputStream();
+ StreamUtils.copyStream( in, out, true );
+ String target = out.toString( "ISO8859-1" );
+ Properties properties = System.getProperties();
+ String path = PropertyResolver.resolve( properties,
target );
+ String expanded = expand( path, query );
+ URI value = URI.create( expanded );
+ return value;
+ }
+ }
+ );
+ return result;
+ }
+ catch( PrivilegedActionException e )
+ {
+ Exception exception = e.getException();
+ if( exception instanceof ArtifactNotFoundException )
+ {
+ final String error =
+ "Link not found: "
+ + uri;
+ throw new LinkNotFoundException( error, uri );
+ }
+ else
+ {
+ throw (IOException) exception;
+ }
+ }
+ }
+
+ private String expand( String artifact, String query )
+ {
+ if( null == query )
+ {
+ return artifact;
+ }
+ int hash = artifact.indexOf( '#' );
+ if( hash > -1 )
+ {
+ String pre = artifact.substring( 0, hash );
+ String post = artifact.substring( hash );
+ return pre + "?" + query + post;
+ }
+ else
+ {
+ return artifact + "?" + query;
+ }
+ }
+
+ private static final class URIHolder
+ {
+ private final URI m_uri;
+ private final URI m_raw;
+ private final String m_query;
+
+ URIHolder( URI uri )
+ {
+ m_uri = uri;
+ if( !Artifact.isRecognized( uri ) )
+ {
+ m_raw = uri;
+ m_query = null;
+ }
+ else
+ {
+ URI base = Artifact.createArtifact( uri ).toURI();
+ String ssp = base.getRawSchemeSpecificPart();
+ int n = ssp.indexOf( '?' );
+ if( n > -1 )
+ {
+ m_query = ssp.substring( n + 1 );
+ String scheme = base.getScheme();
+ String result = ssp.substring( 0, n );
+ String fragment = base.getFragment();
+ try
+ {
+ m_raw = new URI( scheme, result, fragment );
+ }
+ catch( Exception e )
+ {
+ final String error =
+ "Transformation error in ["
+ + uri
+ + "]";
+ throw new TransitRuntimeException( error, e );
+ }
+ }
+ else
+ {
+ m_raw = base;
+ m_query = null;
+ }
+ }
+ }
+
+ URI getBaseURI()
+ {
+ return m_raw;
+ }
+
+ String getQuery()
+ {
+ return m_query;
+ }
+ }
+
+ private byte[] getByteArray( URI uri ) throws IOException
+ {
+ if( null != uri )
+ {
+ return uri.toString().getBytes( "ISO8859-1" );
+ }
+ else
+ {
+ return new byte[0];
+ }
+ }
+}

Added: trunk/main/transit/core/src/main/dpml/transit/StandardMonitor.java
===================================================================
--- trunk/main/transit/core/src/main/dpml/transit/StandardMonitor.java
2007-02-08 23:39:34 UTC (rev 1832)
+++ trunk/main/transit/core/src/main/dpml/transit/StandardMonitor.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2006-2007 Stephen McConnell.
+ *
+ * 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 dpml.transit;
+
+import dpml.util.PID;
+
+import java.io.File;
+import java.net.URL;
+
+import net.dpml.transit.Artifact;
+import net.dpml.transit.Monitor;
+
+import net.dpml.util.Logger;
+
+/**
+ * Event monitor that redirects to an underlying logging channel.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class StandardMonitor implements Monitor
+{
+ //
------------------------------------------------------------------------
+ // state
+ //
------------------------------------------------------------------------
+
+ /**
+ * The assigned logging channel.
+ */
+ private final Logger m_logger;
+
+ //
------------------------------------------------------------------------
+ // constructor
+ //
------------------------------------------------------------------------
+
+ /**
+ * Creation of a new adaptive monitor.
+ * @param logger the underlying logging channel
+ */
+ public StandardMonitor( Logger logger )
+ {
+ m_logger = logger;
+ }
+
+ //
------------------------------------------------------------------------
+ // Monitor
+ //
------------------------------------------------------------------------
+
+ /**
+ * Notify the monitor that an artifact has been requested.
+ * @param artifact the requested artifact
+ */
+ public void resourceRequested( Artifact artifact )
+ {
+ }
+
+ /**
+ * Notify the monitor that an artifact has been added to the local cache.
+ * @param resource the url of the resource added to the local cache
+ * @param localFile the local file resident in the cache
+ */
+ public void addedToLocalCache( URL resource, File localFile )
+ {
+ }
+
+ /**
+ * Notify the monitor that an artifact in the local cache has been
updated.
+ * @param resource the url of the resource updating the local cache
+ * @param localFile the local file that has been updated
+ */
+ public void updatedLocalCache( URL resource, File localFile )
+ {
+ }
+
+ /**
+ * Notify the monitor that an artifact has been removed from the local
cache.
+ * @param resource the url of the resource removed from the local cache
+ * @param localFile the local file removed from the cache
+ */
+ public void removedFromLocalCache( URL resource, File localFile )
+ {
+ if( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug( "removed [" + localFile + "] representing ["
+ resource + "]" );
+ }
+ }
+
+ /**
+ * Notify the monitor of a failed download attempt relative to an
identified host.
+ * @param host the host raising the fail status
+ * @param artifact the requested artifact
+ * @param e the exception causing the failure
+ */
+ public void failedDownloadFromHost( String host, Artifact artifact,
Throwable e )
+ {
+ if( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug(
+ "download failure on ["
+ + host + "] for ["
+ + artifact
+ + "] due to: "
+ + e.getMessage() );
+ }
+ }
+
+ /**
+ * Notify the monitor of a failed download attempt.
+ * @param artifact the requested artifact
+ */
+ public void failedDownload( Artifact artifact )
+ {
+ if( getLogger().isDebugEnabled() )
+ {
+ getLogger().warn( "failed to download " + artifact );
+ }
+ }
+
+ //
------------------------------------------------------------------------
+ // NetworkMonitor
+ //
------------------------------------------------------------------------
+
+ /**
+ * Handle the notification of an update in the download status.
+ *
+ * @param resource the name of the remote resource being downloaded.
+ * @param total the expected number of bytes to be downloaded.
+ * @param count the number of bytes downloaded.
+ */
+ public void notifyUpdate( URL resource, int total, int count )
+ {
+ String path = resource.toString();
+ if( path.startsWith( "file:" ) )
+ {
+ return;
+ }
+ if( ( null != System.getProperty( "ant.home" ) )
+ || ( "true".equals( System.getProperty( "dpml.subprocess" ) ) ) )
+ {
+ if( count == 0 )
+ {
+ if( getLogger().isInfoEnabled() )
+ {
+ getLogger().info(
+ "downloading ["
+ + resource
+ + "] ("
+ + getFranctionalValue( total )
+ + ")" );
+ }
+ }
+ return;
+ }
+
+ if( getLogger().isInfoEnabled() )
+ {
+ String max = getFranctionalValue( total );
+ String value = getFranctionalValue( count );
+ int pad = max.length() - value.length();
+ String level = "[INFO] ";
+ String process = getProcessHeader();
+ StringBuffer buffer = new StringBuffer( process + level );
+ String name = path.substring( path.lastIndexOf( '/' ) + 1 );
+ buffer.append( "(" + CATEGORY+ "): " );
+ buffer.append( "retrieving: " + name + " " );
+ for( int i=0; i < pad; i++ )
+ {
+ buffer.append( " " );
+ }
+ buffer.append( value );
+ buffer.append( "k/" );
+ if( total == 0 )
+ {
+ buffer.append( "?" );
+ }
+ else
+ {
+ buffer.append( max );
+ buffer.append( "k\r" );
+ }
+ if( total == count )
+ {
+ System.out.println( buffer.toString() );
+ }
+ else
+ {
+ System.out.print( buffer.toString() );
+ }
+ }
+ }
+
+ /**
+ * Handle the notification of the completion of of download process.
+ * @param resource the url of the completed resource
+ */
+ public void notifyCompletion( URL resource )
+ {
+ if( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug( "downloaded: " + resource );
+ }
+ }
+
+ //
------------------------------------------------------------------------
+ // implementation
+ //
------------------------------------------------------------------------
+
+ private Logger getLogger()
+ {
+ return m_logger;
+ }
+
+ private String getProcessHeader()
+ {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append( "[" );
+ buffer.append( ID.getValue() );
+ buffer.append( " " );
+ String tag = buffer.toString();
+ return tag.substring( 0, PROCESS_HEADER_WIDTH ) + "] ";
+ }
+
+ /**
+ * Return a string representing the number of kilobytes relative to the
supplied
+ * total bytes.
+ * @param total the byte value
+ * @return the string to log
+ */
+ private static String getFranctionalValue( int total )
+ {
+ final int offset = 3;
+
+ float realTotal = new Float( total ).floatValue();
+ float realK = new Float( KBYTE ).floatValue();
+ float r = ( realTotal / realK );
+
+ String value = new Float( r ).toString();
+ int j = value.indexOf( "." );
+ if( j > -1 )
+ {
+ int q = value.length();
+ int k = q - j;
+ if( k > offset )
+ {
+ return value.substring( 0, j + offset );
+ }
+ else
+ {
+ return value;
+ }
+ }
+ else
+ {
+ return value;
+ }
+ }
+
+ private static final int PROCESS_HEADER_WIDTH = 6;
+
+ private static final int KBYTE = 1024;
+
+ private static final String CATEGORY = "dpml.transit";
+
+ private static final PID ID = new PID();
+
+}

Added: trunk/main/transit/core/src/main/dpml/transit/StreamUtils.java
===================================================================
--- trunk/main/transit/core/src/main/dpml/transit/StreamUtils.java
2007-02-08 23:39:34 UTC (rev 1832)
+++ trunk/main/transit/core/src/main/dpml/transit/StreamUtils.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2004-2007 Stephen J. McConnell.
+ * Copyright 2004 Niclas Hedhman
+ * 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 dpml.transit;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import java.net.URL;
+
+import net.dpml.transit.Monitor;
+
+/**
+ * Utility class that provides support for stream copy operations.
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public final class StreamUtils
+{
+ /**
+ * Disabled constructor.
+ */
+ private StreamUtils()
+ {
+ }
+
+ /**
+ * Buffer size.
+ */
+ private static final int BUFFER_SIZE = 102400;
+
+ /**
+ * Copy a stream.
+ * @param src the source input stream
+ * @param dest the destination output stream
+ * @param closeStreams TRUE if the streams should be closed on completion
+ * @exception IOException if an IO error occurs
+ * @exception NullPointerException if src or destination are null
+ */
+ public static void copyStream(
+ InputStream src, OutputStream dest, boolean closeStreams )
+ throws IOException, NullPointerException
+ {
+ copyStream( null, null, 0, src, dest, closeStreams );
+ }
+
+ /**
+ * Copy a stream.
+ * @param monitor optional network monitor to log updates
+ * @param source the source url
+ * @param expected the expected size in bytes
+ * @param src the source input stream
+ * @param dest the destination output stream
+ * @param closeStreams TRUE if the streams should be closed on completion
+ * @exception IOException if an IO error occurs
+ * @exception NullPointerException if src or destination are null
+ */
+ public static void copyStream(
+ Monitor monitor, URL source, int expected,
+ InputStream src, OutputStream dest, boolean closeStreams )
+ throws IOException, NullPointerException
+ {
+ if( src == null )
+ {
+ throw new NullPointerException( "src" );
+ }
+
+ if( dest == null )
+ {
+ throw new NullPointerException( "dest" );
+ }
+
+ int length;
+ int count = 0; // cumulative total read
+ byte[] buffer = new byte[BUFFER_SIZE];
+ if( !( dest instanceof BufferedOutputStream ) )
+ {
+ dest = new BufferedOutputStream( dest );
+ }
+ if( !( src instanceof BufferedInputStream ) )
+ {
+ src = new BufferedInputStream( src );
+ }
+
+ try
+ {
+ if( null != monitor )
+ {
+ monitor.notifyUpdate( source, expected, 0 );
+ }
+ while( ( length = src.read( buffer ) ) >= 0 )
+ {
+ count = count + length;
+ dest.write( buffer, 0, length );
+ if( null != monitor )
+ {
+ monitor.notifyUpdate( source, expected, count );
+ }
+ }
+ }
+ finally
+ {
+ if( closeStreams )
+ {
+ try
+ {
+ src.close();
+ }
+ catch( Throwable e )
+ {
+ e.printStackTrace();
+ }
+ try
+ {
+ dest.close();
+ }
+ catch( Throwable e )
+ {
+ e.printStackTrace();
+ }
+ }
+ if( null != monitor )
+ {
+ monitor.notifyCompletion( source );
+ }
+ }
+ }
+
+ /**
+ * Compare two streams.
+ * @param in1 the first input stream
+ * @param in2 the second input stream
+ * @return the equality status
+ * @exception IOException if an IO error occurs
+ */
+ public static boolean compareStreams( InputStream in1, InputStream in2 )
+ throws IOException
+ {
+ boolean result = true;
+ do
+ {
+ int v1 = in1.read();
+ int v2 = in2.read();
+ if( v1 != v2 )
+ {
+ return false;
+ }
+ if( v1 == -1 )
+ {
+ break;
+ }
+ } while( true );
+ return result;
+ }
+}

Added: trunk/main/transit/core/src/main/dpml/transit/TransitAuthenticator.java
===================================================================
--- trunk/main/transit/core/src/main/dpml/transit/TransitAuthenticator.java
2007-02-08 23:39:34 UTC (rev 1832)
+++ trunk/main/transit/core/src/main/dpml/transit/TransitAuthenticator.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2004-2007 Stephen McConnell, DPML
+ *
+ * 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 dpml.transit;
+
+import java.net.Authenticator;
+import java.net.PasswordAuthentication;
+
+/**
+ * Transit authenticator contract.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+abstract class TransitAuthenticator
+{
+ /**
+ * Returns the password authenticator.
+ * @param authenticator the default authenticator
+ * @return the password authenticator
+ */
+ abstract PasswordAuthentication resolvePasswordAuthentication(
Authenticator authenticator );
+}

Added:
trunk/main/transit/core/src/main/dpml/transit/TransitAuthenticatorImpl.java
===================================================================
---
trunk/main/transit/core/src/main/dpml/transit/TransitAuthenticatorImpl.java
2007-02-08 23:39:34 UTC (rev 1832)
+++
trunk/main/transit/core/src/main/dpml/transit/TransitAuthenticatorImpl.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2004-2007 Stephen McConnell, DPML
+ * Copyright 2004 Niclas Hedhman, DPML
+ *
+ * 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 dpml.transit;
+
+import java.net.Authenticator;
+import java.net.PasswordAuthentication;
+
+/**
+ * Default authenticator that provides support for username password
+ * based authentication in conjunction with the repository proxy settings.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+final class TransitAuthenticatorImpl
+ extends TransitAuthenticator
+{
+ //
------------------------------------------------------------------------
+ // state
+ //
------------------------------------------------------------------------
+
+ /**
+ * Proxy username.
+ */
+ private final PasswordAuthentication m_authentication;
+
+ //
------------------------------------------------------------------------
+ // constructor
+ //
------------------------------------------------------------------------
+
+ /**
+ * Creation of a new simple authenticator.
+ * @param authenticator a password authenticator
+ * @exception NullPointerException if either the authenticator argument
is null
+ */
+ public TransitAuthenticatorImpl( PasswordAuthentication authenticator )
+ throws NullPointerException
+ {
+ if( authenticator == null )
+ {
+ m_authentication = new PasswordAuthentication( "",
"".toCharArray() );
+ }
+ else
+ {
+ m_authentication = authenticator;
+ }
+ }
+
+ /**
+ * Creation of a new simple authenticator.
+ * @param username the username
+ * @param password the password
+ * @exception NullPointerException if either the username or password
argument is null
+ */
+ public TransitAuthenticatorImpl( String username, String password )
+ throws NullPointerException
+ {
+ if( username == null )
+ {
+ throw new NullPointerException( "username" );
+ }
+ if( password == null )
+ {
+ throw new NullPointerException( "password" );
+ }
+ m_authentication = new PasswordAuthentication( username,
password.toCharArray() );
+ }
+
+ //
------------------------------------------------------------------------
+ // implementation
+ //
------------------------------------------------------------------------
+
+ /**
+ * Returns the password authenticator.
+ * @param authenticator an default authenticator
+ * @return the password authenticator
+ */
+ public PasswordAuthentication resolvePasswordAuthentication(
Authenticator authenticator )
+ {
+ return m_authentication;
+ }
+}

Added: trunk/main/transit/core/src/main/dpml/transit/TransitContext.java
===================================================================
--- trunk/main/transit/core/src/main/dpml/transit/TransitContext.java
2007-02-08 23:39:34 UTC (rev 1832)
+++ trunk/main/transit/core/src/main/dpml/transit/TransitContext.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,467 @@
+/*
+ * Copyright 2004-2005 Niclas Hedhman
+ * Copyright 2005-2007 Stephen McConnell
+ *
+ * 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 dpml.transit;
+
+import java.lang.management.ManagementFactory;
+import java.net.PasswordAuthentication;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Properties;
+import java.util.Hashtable;
+import java.util.ArrayList;
+import java.util.ServiceLoader;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.MBeanException;
+
+import net.dpml.util.Logger;
+import dpml.util.DefaultLogger;
+
+import net.dpml.transit.Artifact;
+import net.dpml.transit.Transit;
+import net.dpml.transit.TransitManager;
+import net.dpml.transit.LinkManager;
+import net.dpml.transit.TransitError;
+import net.dpml.transit.TransitException;
+import net.dpml.transit.Layout;
+import net.dpml.transit.Monitor;
+import net.dpml.transit.ContentHandler;
+import net.dpml.transit.ContentManager;
+
+import dpml.transit.info.TransitDirective;
+import dpml.transit.info.ProxyDirective;
+import dpml.transit.info.CacheDirective;
+import dpml.transit.info.TransitDirective;
+
+/**
+ * Initial context of the Transit system used by protocol handlers.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public final class TransitContext implements TransitManager
+{
+ //------------------------------------------------------------------
+ // static
+ //------------------------------------------------------------------
+
+ /**
+ * Creation of the transit context. If the transit context has already
+ * been established the method returns the singleton context otherwise a
new
+ * context is created relative to the authoritve url and returned.
+ * @param directive the transit configuration directive
+ * @return the secured transit context
+ * @exception TransitException if an error occurs during context creation
+ * @exception NullPointerException if the supplied configration directive
is null
+ * and an instance of this class has not been created already.
+ */
+ public static synchronized TransitContext create( TransitDirective
directive )
+ throws TransitException, NullPointerException
+ {
+ if( null == directive )
+ {
+ throw new NullPointerException( "directive" );
+ }
+
+ if( m_CONTEXT != null )
+ {
+ final String error =
+ "Transit context already exists.";
+ throw new IllegalStateException( error );
+ }
+
+ Logger logger = new DefaultLogger( "dpml.transit" );
+ if( logger.isTraceEnabled() )
+ {
+ logger.trace( "creating new transit context" );
+ }
+
+ try
+ {
+ String jmxEnabled = System.getProperty( "dpml.jmx.enabled" );
+ if( "true".equals( jmxEnabled ) )
+ {
+ MBeanServer server =
ManagementFactory.getPlatformMBeanServer();
+ m_CONTEXT = new TransitContext( server, directive, logger );
+ }
+ else
+ {
+ m_CONTEXT = new TransitContext( null, directive, logger );
+ }
+ }
+ catch( TransitException e )
+ {
+ throw e;
+ }
+ catch( Exception e )
+ {
+ String error = "Transit context creation error.";
+ throw new TransitException( error, e );
+ }
+
+ if( logger.isTraceEnabled() )
+ {
+ logger.trace( "transit context established" );
+ }
+ return m_CONTEXT;
+ }
+
+ /**
+ * Return the singleton context.
+ * @return the secure context
+ */
+ public synchronized static TransitContext getInstance()
+ {
+ if( null == m_CONTEXT )
+ {
+ final String error =
+ "Transit context has not been initialized.";
+ throw new IllegalStateException( error );
+ }
+ else
+ {
+ return m_CONTEXT;
+ }
+ }
+
+ //------------------------------------------------------------------
+ // state
+ //------------------------------------------------------------------
+
+ /**
+ * The configuration directive.
+ */
+ private final TransitDirective m_directive;
+
+ /**
+ * The cache handler.
+ */
+ private final DefaultCacheHandler m_cacheHandler;
+
+ /**
+ * The LinkManager instance.
+ */
+ private final LinkManager m_linkManager;
+
+ /**
+ * Logging channel.
+ */
+ private final Logger m_logger;
+
+ /**
+ * The singleton router.
+ */
+ private final DefaultMonitor m_monitor;
+
+ //------------------------------------------------------------------
+ // constructors
+ //------------------------------------------------------------------
+
+ /**
+ * Creation of a new secured transit context.
+ * @param server JMX server (may be null)
+ * @param directive the transit configuration directive
+ * @param logger the assigned logging channel
+ * @exception IOException if an I/O error occurs
+ */
+ private TransitContext(
+ MBeanServer server, TransitDirective directive, Logger logger ) throws
Exception
+ {
+ m_directive = directive;
+ m_logger = logger;
+
+ if( null != server )
+ {
+ Hashtable<String,String> table = new Hashtable<String,String>();
+ table.put( "type", "System" );
+ ObjectName name =
+ ObjectName.getInstance( "net.dpml.transit", table );
+ server.registerMBean( this, name );
+ }
+
+ m_monitor = new DefaultMonitor();
+ Logger cacheLogger = logger.getChildLogger( "cache" );
+ CacheDirective cacheDirective = directive.getCacheDirective();
+ m_cacheHandler = new DefaultCacheHandler( server, this,
cacheDirective, cacheLogger );
+ m_linkManager = new StandardLinkManager();
+ ProxyDirective proxy = directive.getProxyDirective();
+ setupProxy( proxy );
+ }
+
+ //------------------------------------------------------------------
+ // implementation
+ //------------------------------------------------------------------
+
+ /**
+ * Returns the Transit monitor.
+ * @return the monitor
+ */
+ public Monitor getMonitor()
+ {
+ return m_monitor;
+ }
+
+ /**
+ * Add a monitor to Transit.
+ * @param monitor the monitor
+ */
+ public void addMonitor( Monitor monitor )
+ {
+ m_monitor.addMonitor( monitor );
+ }
+
+ /**
+ * Return a content handler for the given artifact type.
+ * @param type the artifact type
+ * @return the content handler or null if unknown
+ */
+ public ContentHandler getContentHandler( String type )
+ {
+ ContentHandler[] handlers = getContentHandlers();
+ for( ContentHandler handler : handlers )
+ {
+ String t = handler.getType();
+ if( type.equals( t ) )
+ {
+ if( m_logger.isTraceEnabled() )
+ {
+ m_logger.trace(
+ "selecting handler ["
+ + handler.getClass().getName()
+ + "] for the type ["
+ + type
+ + "]" );
+ }
+ return handler;
+ }
+ }
+ return null;
+ }
+
+ private ContentHandler[] getContentHandlers()
+ {
+ ArrayList<ContentHandler> list = new ArrayList<ContentHandler>();
+ ServiceLoader<ContentHandler> loaders =
+ ServiceLoader.load( ContentHandler.class );
+ for( ContentHandler handler : loaders )
+ {
+ m_logger.trace( "loaded handler: " + handler );
+ list.add( handler );
+ }
+ return (ContentHandler[]) list.toArray( new ContentHandler[0] );
+ }
+
+ /**
+ * Return the cache layout.
+ * @return the layout
+ */
+ public Layout getCacheLayout()
+ {
+ return getCacheHandler().getLayout();
+ }
+
+ /**
+ * Return the cache handler.
+ * @return the cache handler
+ */
+ public Cache getCacheHandler()
+ {
+ return m_cacheHandler;
+ }
+
+ /**
+ * Return the link manager.
+ * @return the cache handler
+ */
+ public LinkManager getLinkManager()
+ {
+ return m_linkManager;
+ }
+
+ /**
+ * Return the Transit proxy host
+ * @return the host name
+ */
+ public String getProxyHost()
+ {
+ return m_directive.getProxyDirective().getHost();
+ }
+
+ /**
+ * Return the Transit cache directory path.
+ * @return the cache path
+ */
+ public String getVersion()
+ {
+ return Transit.VERSION;
+ }
+
+ /**
+ * Return the Transit home directory.
+ * @return the home directory
+ */
+ public String getHome()
+ {
+ return Transit.HOME.toString();
+ }
+
+ /**
+ * Return the Transit data directory.
+ * @return the data directory
+ */
+ public String getData()
+ {
+ return Transit.DATA.toString();
+ }
+
+ /**
+ * Return the Transit prefs directory.
+ * @return the prefs directory
+ */
+ public String getPrefs()
+ {
+ return Transit.PREFS.toString();
+ }
+
+ /**
+ * Return the Transit share directory.
+ * @return the share directory
+ */
+ public String getShare()
+ {
+ return Transit.SYSTEM.toString();
+ }
+
+ //------------------------------------------------------------------
+ // internals
+ //------------------------------------------------------------------
+
+ private synchronized void setupProxy( ProxyDirective directive ) throws
Exception
+ {
+ if( null == directive )
+ {
+ return;
+ }
+
+ String host = directive.getHost();
+ if( null != host )
+ {
+ URL proxy = new URL( host );
+ PasswordAuthentication auth = getPasswordAuthentication(
directive );
+ if( null != auth )
+ {
+ TransitAuthenticator ta = new TransitAuthenticatorImpl( auth
);
+ RequestIdentifier id = getRequestIdentifier( proxy );
+ DelegatingAuthenticator da =
DelegatingAuthenticator.getInstance();
+ da.addTransitAuthenticator( ta, id );
+ }
+
+ int port = proxy.getPort();
+ Properties system = System.getProperties();
+ system.put( "http.proxyHost", proxy );
+ system.put( "http.proxyPort", "" + port );
+ String[] excludes = directive.getExcludes();
+ String path = toExcludesPath( excludes );
+ if( null != path )
+ {
+ system.put( "http.nonProxyHosts", path );
+ }
+ }
+ }
+
+ private PasswordAuthentication getPasswordAuthentication( ProxyDirective
directive )
+ {
+ String username = directive.getUsername();
+ if( null != username )
+ {
+ return new PasswordAuthentication( username,
directive.getPassword() );
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ private RequestIdentifier getRequestIdentifier( URL url )
+ {
+ if( null == url )
+ {
+ return null;
+ }
+ else
+ {
+ String protocol = url.getProtocol();
+ String scheme = "";
+ String prompt = "";
+ int port = url.getPort();
+ String host = url.getHost();
+ return new RequestIdentifier( host, port, protocol, scheme,
prompt );
+ }
+ }
+
+ private Logger getLogger()
+ {
+ return m_logger;
+ }
+
+ //------------------------------------------------------------------
+ // static (utils)
+ //------------------------------------------------------------------
+
+ /**
+ * Resolve the list of host names to be assigned as non-proxied hosts. If
proxy
+ * excludes are defined the string returned contains the host name
(wilcards allowed)
+ * separated by the "|" character. If no proxy excludes are defined the
value returned
+ * shall be null. The implementation reads the set of attribute names
associated
+ * with a preferences node named "excludes". Each attribute name is
appended to
+ * a single string where names are separated by the "|" character.
+ *
+ * @param names an array of named excludes
+ * @return a string containing a sequence of excluded hosts (possibly
null)
+ */
+ private static String toExcludesPath( String[] names )
+ {
+ String spec = null;
+ for( int i=0; i < names.length; i++ )
+ {
+ String name = names[i];
+ if( null == spec )
+ {
+ spec = name;
+ }
+ else
+ {
+ spec = spec + "|" + name;
+ }
+ }
+ return spec;
+ }
+
+ /**
+ * The namespace string for transit related properties.
+ */
+ public static final String DOMAIN = "dpml.transit";
+
+ /**
+ * The singleton transit context.
+ */
+ private static TransitContext m_CONTEXT;
+}

Added: trunk/main/transit/core/src/main/dpml/transit/ZipCache.java
===================================================================
--- trunk/main/transit/core/src/main/dpml/transit/ZipCache.java 2007-02-08
23:39:34 UTC (rev 1832)
+++ trunk/main/transit/core/src/main/dpml/transit/ZipCache.java 2007-02-08
23:42:59 UTC (rev 1833)
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2004-2007 Stephen J. McConnell.
+ * Copyright 2004 Niclas Hedhman
+ * 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 dpml.transit;
+
+import java.util.HashMap;
+import java.util.Iterator;
+
+import java.util.zip.ZipFile;
+
+import net.dpml.transit.Artifact;
+
+/**
+ * Internal cache.
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+class ZipCache implements Runnable
+{
+ private static final int TIME_TO_LIVE = 30000;
+ private static final int DELAY = 10000;
+
+ private HashMap<Artifact, Entry> m_store;
+ private long m_timeToLive;
+ private Thread m_thread;
+
+ /**
+ * Internal zip cache constructor.
+ */
+ ZipCache()
+ {
+ m_store = new HashMap<Artifact, Entry>();
+ m_timeToLive = TIME_TO_LIVE;
+ }
+
+ ZipFile get( Artifact key )
+ {
+ synchronized( this ) // ensure no ConcurrentModificationException
can occur.
+ {
+ Entry entry = (Entry) m_store.get( key );
+ if( entry == null )
+ {
+ return null;
+ }
+ ZipFile zip = entry.m_file;
+ return zip;
+ }
+ }
+
+ void put( Artifact key, ZipFile file )
+ {
+ synchronized( this ) // ensure no ConcurrentModificationException
can occur.
+ {
+ Entry entry = new Entry( file );
+ m_store.put( key, entry );
+ if( m_thread == null )
+ {
+ m_thread = new Thread( this, "DPML Transit Zip Cache
Cleaner" );
+ m_thread.setDaemon( true );
+ m_thread.start();
+ }
+ }
+ }
+
+ /**
+ * Start the cache handler.
+ */
+ public void run()
+ {
+ while( true )
+ {
+ try
+ {
+ synchronized( this )
+ {
+ long now = System.currentTimeMillis();
+ Iterator list = m_store.values().iterator();
+ while( list.hasNext() )
+ {
+ Entry entry = (Entry) list.next();
+ if( entry.m_collectTime < now )
+ {
+ entry.m_file.close();
+ list.remove();
+ }
+ }
+ if( m_store.size() == 0 )
+ {
+ m_thread = null;
+ break;
+ }
+ wait( DELAY );
+ }
+ }
+ catch( Exception e )
+ {
+ // Can not happen?
+ // Just ignore and it will be handled in the next round.
+ e.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * Internal class that maintains a cache entry.
+ */
+ class Entry
+ {
+ private ZipFile m_file;
+ private long m_collectTime;
+
+ /**
+ * Creation of a new zip cache entry.
+ * @param file the zip file to cache
+ */
+ Entry( ZipFile file )
+ {
+ m_file = file;
+ m_collectTime = System.currentTimeMillis() + m_timeToLive;
+ }
+
+ /**
+ * Test this objexct for equality with another.
+ * @param obj the other object
+ * @return the equaility status
+ */
+ public boolean equals( Object obj )
+ {
+ if( obj == null )
+ {
+ return false;
+ }
+ if( !obj.getClass().equals( Entry.class ) )
+ {
+ return false;
+ }
+ Entry other = (Entry) obj;
+
+ if( !m_file.equals( other.m_file ) )
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Retun the instance hashcode.
+ * @return the hashcode value
+ */
+ public int hashCode()
+ {
+ return m_file.hashCode();
+ }
+
+ /**
+ * Return a string represention of the cache entry.
+ * @return the string value
+ */
+ public String toString()
+ {
+ return "Entry[" + m_file + ", " + m_collectTime + "]";
+ }
+ }
+}

Copied: trunk/main/transit/core/src/main/dpml/transit/artifact (from rev
1810, trunk/main/transit/core/src/main/net/dpml/transit/artifact)

Deleted:
trunk/main/transit/core/src/main/dpml/transit/artifact/ArtifactAlreadyExistsException.java
===================================================================
---
trunk/main/transit/core/src/main/net/dpml/transit/artifact/ArtifactAlreadyExistsException.java
2007-01-10 20:29:19 UTC (rev 1810)
+++
trunk/main/transit/core/src/main/dpml/transit/artifact/ArtifactAlreadyExistsException.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -1,71 +0,0 @@
-/*
- * Copyright 2004-2005 Stephen J. McConnell.
- *
- * 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 net.dpml.transit.artifact;
-
-import net.dpml.transit.Artifact;
-
-/**
- * Exception to indicate that the Artifact already exists in the cache and
- * can therefor not be written to.
- *
- * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
- * @version @PROJECT-VERSION@
- */
-public class ArtifactAlreadyExistsException extends ArtifactException
-{
- /**
- * Serial version identifier.
- */
- static final long serialVersionUID = 1L;
-
- //
------------------------------------------------------------------------
- // state
- //
------------------------------------------------------------------------
-
- /**
- * The artifact that we tried to write to.
- */
- private final Artifact m_artifact;
-
- //
------------------------------------------------------------------------
- // constructor
- //
------------------------------------------------------------------------
-
- /**
- * Construct a new <code>ArtifactAlreadyExistsException</code> instance.
- *
- * @param message the exception message
- * @param artifact the subject artifact
- */
- public ArtifactAlreadyExistsException( final String message, final
Artifact artifact )
- {
- super( message );
- m_artifact = artifact;
- }
-
- /**
- * Returns the Artifact that were attempted to be written to.
- * @return the subject artifact
- */
- public Artifact getArtifact()
- {
- return m_artifact;
- }
-}
-

Deleted:
trunk/main/transit/core/src/main/dpml/transit/artifact/ArtifactException.java
===================================================================
---
trunk/main/transit/core/src/main/net/dpml/transit/artifact/ArtifactException.java
2007-01-10 20:29:19 UTC (rev 1810)
+++
trunk/main/transit/core/src/main/dpml/transit/artifact/ArtifactException.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -1,62 +0,0 @@
-/*
- * Copyright 2004-2005 Stephen J. McConnell.
- * Copyright 2004 Niclas Hedhman.
- *
- * 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 net.dpml.transit.artifact;
-
-import net.dpml.transit.TransitException;
-
-/**
- * Exception to indicate that there was an Artifact related error.
- *
- * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
- * @version @PROJECT-VERSION@
- */
-public class ArtifactException extends TransitException
-{
- /**
- * Serial version identifier.
- */
- static final long serialVersionUID = 1L;
-
- //
------------------------------------------------------------------------
- // constructor
- //
------------------------------------------------------------------------
-
- /**
- * Construct a new <code>ArtifactException</code> instance.
- *
- * @param message The detail message for this exception.
- */
- public ArtifactException( final String message )
- {
- super( message );
- }
-
- /**
- * Construct a new <code>ArtifactException</code> instance.
- *
- * @param message The detail message for this exception.
- * @param cause the root cause of the exception
- */
- public ArtifactException( final String message, final Throwable cause )
- {
- super( message, cause );
- }
-}
-

Deleted:
trunk/main/transit/core/src/main/dpml/transit/artifact/ArtifactNotFoundException.java
===================================================================
---
trunk/main/transit/core/src/main/net/dpml/transit/artifact/ArtifactNotFoundException.java
2007-01-10 20:29:19 UTC (rev 1810)
+++
trunk/main/transit/core/src/main/dpml/transit/artifact/ArtifactNotFoundException.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -1,70 +0,0 @@
-/*
- * Copyright 2004-2005 Stephen J. McConnell.
- *
- * 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 net.dpml.transit.artifact;
-
-import java.net.URI;
-
-/**
- * Exception to indicate that an Artifact could not be located.
- *
- * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
- * @version @PROJECT-VERSION@
- */
-public class ArtifactNotFoundException extends ArtifactException
-{
- /**
- * Serial version identifier.
- */
- static final long serialVersionUID = 1L;
-
- //
------------------------------------------------------------------------
- // state
- //
------------------------------------------------------------------------
-
- /**
- * The artifact that we not found.
- */
- private final URI m_artifact;
-
- //
------------------------------------------------------------------------
- // constructor
- //
------------------------------------------------------------------------
-
- /**
- * Construct a new <code>ArtifactNotFoundException</code> instance.
- *
- * @param message The detail message for this exception.
- * @param artifact the subject artifact
- */
- public ArtifactNotFoundException( final String message, final URI
artifact )
- {
- super( message );
- m_artifact = artifact;
- }
-
- /**
- * Returns the uri that could not be found.
- * @return the subject uri
- */
- public URI getURI()
- {
- return m_artifact;
- }
-}
-

Modified:
trunk/main/transit/core/src/main/dpml/transit/artifact/ArtifactURLConnection.java
===================================================================
---
trunk/main/transit/core/src/main/net/dpml/transit/artifact/ArtifactURLConnection.java
2007-01-10 20:29:19 UTC (rev 1810)
+++
trunk/main/transit/core/src/main/dpml/transit/artifact/ArtifactURLConnection.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -1,6 +1,6 @@
/*
* Copyright 2004 Niclas Hedhman
- * Copyright 2004-2006 Stephen J. McConnell
+ * Copyright 2004-2007 Stephen J. McConnell
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,27 +17,23 @@
* limitations under the License.
*/

-package net.dpml.transit.artifact;
+package dpml.transit.artifact;

+import dpml.transit.TransitContext;
+import dpml.transit.Cache;
+
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.File;
-import java.net.UnknownServiceException;
-import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.net.URISyntaxException;

import net.dpml.transit.Artifact;
import net.dpml.transit.Transit;
-import net.dpml.transit.SecuredTransitContext;
-import net.dpml.transit.CacheHandler;
+import net.dpml.transit.ContentHandler;

-import net.dpml.lang.Part;
-
-import net.dpml.util.MimeTypeHandler;
-
/**
* The connection handler for URLs based on the "artifact" protocol family.
* @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
@@ -52,7 +48,7 @@
/**
* Transit context.
*/
- private final SecuredTransitContext m_context;
+ private final TransitContext m_context;

/**
* Artifact.
@@ -67,7 +63,7 @@
/**
* The connected state.
*/
- private boolean m_connected;
+ private boolean m_connected = false;

//
------------------------------------------------------------------------
// constructor
@@ -80,7 +76,7 @@
* @exception NullPointerException if the url argument is null
* @exception IOException if the url argument is invalid
*/
- ArtifactURLConnection( URL url, SecuredTransitContext context )
+ ArtifactURLConnection( URL url, TransitContext context )
throws NullPointerException, IOException
{
super( url );
@@ -153,7 +149,7 @@
throws IOException
{
connect();
- CacheHandler cache = m_context.getCacheHandler();
+ Cache cache = m_context.getCacheHandler();
if( null != m_reference )
{
return cache.getResource( m_artifact, m_reference );
@@ -172,7 +168,7 @@
public OutputStream getOutputStream()
throws IOException
{
- CacheHandler cache = m_context.getCacheHandler();
+ Cache cache = m_context.getCacheHandler();
return cache.createOutputStream( m_artifact );
}

@@ -194,10 +190,11 @@
public Object getContent()
throws IOException
{
- Object content = getContent( new Class[0] );
- if( content != null )
+ String type = m_artifact.getType();
+ ContentHandler handler = m_context.getContentHandler( type );
+ if( null != handler )
{
- return content;
+ return handler.getContent( this );
}
else
{
@@ -219,47 +216,23 @@
// attempt to resolve this locally as we may be dealing
// with Depot references to the artifact File
//
-
- for( int i=0; i < classes.length; i++ )
+
+ if( ( classes.length == 1 ) && ( classes[0] == File.class ) )
{
- Class c = classes[i];
- if( c.equals( File.class ) )
- {
- return m_context.getCacheHandler().getLocalFile( m_artifact
);
- }
+ return m_context.getCacheHandler().getLocalFile( m_artifact );
}
-
- String type = m_artifact.getType();

- //
- // if the type is a plugin then handle this directly
- //
-
- if( "part".equals( type ) )
- {
- URI uri = m_artifact.toURI();
- Part part = Part.load( uri );
- return part.getContent( classes );
- }
-
- //
- // otherwise fallback on the default jvm content handling
- //
-
- try
+ connect();
+ String type = m_artifact.getType();
+ ContentHandler handler = m_context.getContentHandler( type );
+ if( null != handler )
{
- Object content = super.getContent( classes );
- if( content != null )
- {
- return content;
- }
+ return handler.getContent( this, classes );
}
- catch( UnknownServiceException use )
+ else
{
- boolean ignoreThis = true;
+ return super.getContent( classes );
}
-
- return null;
}

//
------------------------------------------------------------------------

Modified: trunk/main/transit/core/src/main/dpml/transit/artifact/Handler.java
===================================================================
--- trunk/main/transit/core/src/main/net/dpml/transit/artifact/Handler.java
2007-01-10 20:29:19 UTC (rev 1810)
+++ trunk/main/transit/core/src/main/dpml/transit/artifact/Handler.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -1,5 +1,5 @@
/*
- * Copyright 2004-2005 Stephen J. McConnell.
+ * Copyright 2004-2007 Stephen J. McConnell.
* Copyright 2004 Niclas Hedhman
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,8 +16,11 @@
* limitations under the License.
*/

-package net.dpml.transit.artifact;
+package dpml.transit.artifact;

+import dpml.transit.TransitContext;
+import dpml.util.DefaultLogger;
+
import java.io.IOException;
import java.io.PrintWriter;

@@ -28,8 +31,9 @@
import java.security.PrivilegedAction;

import net.dpml.transit.Transit;
+import net.dpml.transit.TransitError;
import net.dpml.transit.TransitRuntimeException;
-import net.dpml.transit.SecuredTransitContext;
+import net.dpml.util.Logger;

/**
* The artifact URL protocol handler.
@@ -48,36 +52,6 @@
private static final int BUFFER_SIZE = 100;

//
------------------------------------------------------------------------
- // state
- //
------------------------------------------------------------------------
-
- /**
- * The transit context.
- */
- private SecuredTransitContext m_context;
-
- //
------------------------------------------------------------------------
- // constructor
- //
------------------------------------------------------------------------
-
- /**
- * Creation of a new transit artifact protocol handler.
- */
- public Handler()
- {
- try
- {
- Transit.getInstance();
- m_context = SecuredTransitContext.getInstance();
- }
- catch( RuntimeException e )
- {
- e.printStackTrace();
- throw e;
- }
- }
-
- //
------------------------------------------------------------------------
// implementation
//
------------------------------------------------------------------------

@@ -91,8 +65,26 @@
protected URLConnection openConnection( final URL url )
throws IOException
{
- return new ArtifactURLConnection( url, m_context );
+ checkTransitInitialization( url );
+ TransitContext context = TransitContext.getInstance();
+ return new ArtifactURLConnection( url, context );
}
+
+ private void checkTransitInitialization( URL url )
+ {
+ try
+ {
+ Transit.getInstance();
+ }
+ catch( TransitError e )
+ {
+ final String error =
+ "Internal error while resolving the Transit instance while
handling the url ["
+ + url
+ + "].";
+ throw new TransitRuntimeException( error, e );
+ }
+ }

/**
* Return the external representation of the supplied url.
@@ -275,7 +267,7 @@
final String ref = version; // final String ref = null;
final String finalPath = path;
AccessController.doPrivileged(
- new PrivilegedAction()
+ new PrivilegedAction<Object>()
{
public Object run()
{
@@ -287,20 +279,11 @@
}
catch( Throwable e )
{
- try
- {
- PrintWriter log = Transit.getInstance().getLogWriter();
- String message = "Unable to parse the URL: "
- + dest + ", " + spec + ", " + start + ", " + limit;
- log.println( message );
- log.println(
"---------------------------------------------------" );
- e.printStackTrace( log );
- }
- catch( TransitRuntimeException f )
- {
- f.printStackTrace();
- e.printStackTrace();
- }
+ final String message =
+ "Internal error while attempting to parse url: "
+ + dest + ", " + spec + ", " + start + ", " + limit;
+ Logger logger = new DefaultLogger( "dpml.transit.artifact" );
+ logger.error( message, e );
}
}


Copied:
trunk/main/transit/core/src/main/dpml/transit/artifact/MimeTypeHandler.java
(from rev 1789,
trunk/main/transit/core/src/main/net/dpml/util/MimeTypeHandler.java)
===================================================================
--- trunk/main/transit/core/src/main/net/dpml/util/MimeTypeHandler.java
2006-11-30 21:08:46 UTC (rev 1789)
+++
trunk/main/transit/core/src/main/dpml/transit/artifact/MimeTypeHandler.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2007 Stephen J. McConnell.
+ * Copyright 2004-2005 Niclas Hedhman.
+ *
+ * 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 dpml.transit.artifact;
+
+import java.util.HashMap;
+
+/**
+ * Mimetype utility handler.
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+final class MimeTypeHandler
+{
+ //
------------------------------------------------------------------------
+ // static
+ //
------------------------------------------------------------------------
+
+ /**
+ * Static mime type table of artifact types to mimetype strings.
+ */
+ private static final HashMap<String, String> MIME_TYPES = new
HashMap<String, String>();
+
+ static
+ {
+ MIME_TYPES.put( "plugin", "text/x-dpml-plugin" );
+ MIME_TYPES.put( "conf", "text/x-dpml-conf" );
+ MIME_TYPES.put( "jar", "application/x-jar" );
+ MIME_TYPES.put( "zip", "application/x-zip" );
+ MIME_TYPES.put( "pdf", "application/pdf" );
+ MIME_TYPES.put( "png", "image/png" );
+ MIME_TYPES.put( "gif", "image/gif" );
+ MIME_TYPES.put( "jpg", "image/jpg" );
+ MIME_TYPES.put( "link", "application/x-dpml-link" );
+ MIME_TYPES.put( "part", "application/x-dpml-part" );
+ }
+
+ /**
+ * Return the mimetype given a artifact type.
+ * @param artifactType the artifact type such as "part", "jar", etc.
+ * @return the matching mimetype of null if unknown
+ */
+ public static String getMimeType( String artifactType )
+ {
+ return MIME_TYPES.get( artifactType );
+ }
+
+ /**
+ * Returns the number of MimeTypes that has been defined.
+ *
+ * Only for use with testcases.
+ * @return the known mimetype count
+ */
+ public static int getMimeTypesSize()
+ {
+ return MIME_TYPES.size();
+ }
+
+ //
------------------------------------------------------------------------
+ // constructor
+ //
------------------------------------------------------------------------
+
+ /**
+ * Disabled constructor.
+ */
+ private MimeTypeHandler()
+ {
+ // disable
+ }
+}
\ No newline at end of file

Added:
trunk/main/transit/core/src/main/dpml/transit/artifact/package-info.java
===================================================================
---
trunk/main/transit/core/src/main/net/dpml/transit/artifact/package-info.java
2007-01-10 20:29:19 UTC (rev 1810)
+++ trunk/main/transit/core/src/main/dpml/transit/artifact/package-info.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2004-2007 Stephen J. McConnell.
+ *
+ * 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.
+ */
+
+/**
+ * Transit <tt>artifact</tt> protocol handler.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+package dpml.transit.artifact;

Deleted: trunk/main/transit/core/src/main/dpml/transit/artifact/package.html
===================================================================
--- trunk/main/transit/core/src/main/net/dpml/transit/artifact/package.html
2007-01-10 20:29:19 UTC (rev 1810)
+++ trunk/main/transit/core/src/main/dpml/transit/artifact/package.html
2007-02-08 23:42:59 UTC (rev 1833)
@@ -1,8 +0,0 @@
-
-<body>
-<p>
-Core protocol handler for uris of the form
-<code>artifact:[type]/[group]/[name]#[version]</code>.
-</p>
-</body>
-

Copied: trunk/main/transit/core/src/main/dpml/transit/info (from rev 1810,
trunk/main/transit/core/src/main/net/dpml/transit/info)

Modified:
trunk/main/transit/core/src/main/dpml/transit/info/CacheDirective.java
===================================================================
---
trunk/main/transit/core/src/main/net/dpml/transit/info/CacheDirective.java
2007-01-10 20:29:19 UTC (rev 1810)
+++ trunk/main/transit/core/src/main/dpml/transit/info/CacheDirective.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -16,11 +16,12 @@
* limitations under the License.
*/

-package net.dpml.transit.info;
+package dpml.transit.info;

import java.util.Arrays;
+import java.io.Serializable;

-import net.dpml.lang.AbstractDirective;
+import dpml.util.ObjectUtils;

/**
* Description of the Transit cache configuration.
@@ -28,7 +29,7 @@
* @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
* @version @PROJECT-VERSION@
*/
-public class CacheDirective extends AbstractDirective
+public class CacheDirective implements Serializable
{
/**
* Default cache path.
@@ -51,20 +52,14 @@
public static final String LOCAL_LAYOUT = "modern";

/**
- * Empty layout array.
- */
- public static final LayoutDirective[] EMPTY_LAYOUTS = new
LayoutDirective[0];
-
- /**
* Empty resource host array.
*/
public static final HostDirective[] EMPTY_HOSTS = new HostDirective[0];
-
+
private final String m_cache;
private final String m_cacheLayout;
private final String m_local;
private final String m_localLayout;
- private final LayoutDirective[] m_layouts;
private final HostDirective[] m_hosts;

/**
@@ -73,22 +68,33 @@
public CacheDirective()
{
this(
- CACHE_PATH, CACHE_LAYOUT, LOCAL_PATH, LOCAL_LAYOUT, EMPTY_LAYOUTS,
EMPTY_HOSTS );
+ CACHE_PATH, CACHE_LAYOUT, LOCAL_PATH, LOCAL_LAYOUT,
+ EMPTY_HOSTS );
}

/**
* Create a new CacheDirective.
+ * @param hosts the assigned remmote hosts
+ */
+ public CacheDirective( HostDirective[] hosts )
+ {
+ this(
+ CACHE_PATH, CACHE_LAYOUT, LOCAL_PATH, LOCAL_LAYOUT,
+ hosts );
+ }
+
+ /**
+ * Create a new CacheDirective.
* @param cache the cache directory path
* @param cacheLayout the cache layout strategy
* @param local the local repository path
* @param localLayout the local repository layout strategy
- * @param layouts an array of extended layout descriptors
- * @param hosts an array of supplimentary host descriptors
+ * @param hosts an array of supplimentary host directives
* @exception NullPointerException if the cache, local, or layout
argument is null
*/
public CacheDirective(
String cache, String cacheLayout, String local, String localLayout,
- LayoutDirective[] layouts, HostDirective[] hosts )
+ HostDirective[] hosts )
throws NullPointerException
{
if( null == cache )
@@ -113,15 +119,6 @@
m_local = local;
m_localLayout = localLayout;

- if( null == layouts )
- {
- m_layouts = new LayoutDirective[0];
- }
- else
- {
- m_layouts = layouts;
- }
-
if( null == hosts )
{
m_hosts = new HostDirective[0];
@@ -175,16 +172,6 @@
/**
* Return the supplimentary layout plugin configurations.
*
- * @return the layout directives
- */
- public LayoutDirective[] getLayoutDirectives()
- {
- return m_layouts;
- }
-
- /**
- * Return the supplimentary layout plugin configurations.
- *
* @return the host directives
*/
public HostDirective[] getHostDirectives()
@@ -199,32 +186,32 @@
*/
public boolean equals( Object other )
{
- if( super.equals( other ) && ( other instanceof CacheDirective ) )
+ if( other instanceof CacheDirective )
{
CacheDirective directive = (CacheDirective) other;
- if( !equals( m_cache, directive.m_cache ) )
+ if( !ObjectUtils.equals( m_cache, directive.m_cache ) )
{
return false;
}
- else if( !equals( m_cacheLayout, directive.m_cacheLayout ) )
+ else if( !ObjectUtils.equals( m_cacheLayout,
directive.m_cacheLayout ) )
{
return false;
}
- else if( !equals( m_local, directive.m_local ) )
+ else if( !ObjectUtils.equals( m_local, directive.m_local ) )
{
return false;
}
- else if( !equals( m_localLayout, directive.m_localLayout ) )
+ else if( !ObjectUtils.equals( m_localLayout,
directive.m_localLayout ) )
{
return false;
}
- else if( !Arrays.equals( m_layouts, directive.m_layouts ) )
+ else if( !Arrays.equals( m_hosts, directive.m_hosts ) )
{
return false;
}
else
{
- return Arrays.equals( m_hosts, directive.m_hosts );
+ return true;
}
}
else
@@ -239,13 +226,12 @@
*/
public int hashCode()
{
- int hash = super.hashCode();
- hash ^= hashValue( m_cache );
- hash ^= hashValue( m_cacheLayout );
- hash ^= hashValue( m_local );
- hash ^= hashValue( m_localLayout );
- hash ^= hashArray( m_layouts );
- hash ^= hashArray( m_hosts );
+ int hash = getClass().hashCode();
+ hash ^= ObjectUtils.hashValue( m_cache );
+ hash ^= ObjectUtils.hashValue( m_cacheLayout );
+ hash ^= ObjectUtils.hashValue( m_local );
+ hash ^= ObjectUtils.hashValue( m_localLayout );
+ hash ^= ObjectUtils.hashArray( m_hosts );
return hash;
}
}

Deleted:
trunk/main/transit/core/src/main/dpml/transit/info/CodeBaseDirective.java
===================================================================
---
trunk/main/transit/core/src/main/net/dpml/transit/info/CodeBaseDirective.java
2007-01-10 20:29:19 UTC (rev 1810)
+++ trunk/main/transit/core/src/main/dpml/transit/info/CodeBaseDirective.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -1,125 +0,0 @@
-/*
- * Copyright 2005 Stephen J. McConnell.
- *
- * 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 net.dpml.transit.info;
-
-import java.net.URI;
-import java.util.Arrays;
-
-import net.dpml.lang.AbstractDirective;
-import net.dpml.lang.ValueDirective;
-
-/**
- * The CodeBaseDirective is immutable datastructure used to
- * describe a codebase.
- *
- * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
- * @version @PROJECT-VERSION@
- */
-public class CodeBaseDirective extends AbstractDirective
-{
- private final URI m_codebase;
- private final ValueDirective[] m_parameters;
-
- /**
- * Creation of a new codebase descriptor.
- * @param codebase the codebase uri
- * @param parameters an array of plugin parameter descriptors
- */
- public CodeBaseDirective( URI codebase, ValueDirective[] parameters )
- {
- if( null == codebase )
- {
- throw new NullPointerException( "codebase" );
- }
- m_codebase = codebase;
- if( null == parameters )
- {
- throw new NullPointerException( "parameters" );
- }
- m_parameters = parameters;
- }
-
- /**
- * Return the codebase URI.
- *
- * @return the codebase uri
- */
- public URI getCodeBaseURI()
- {
- return m_codebase;
- }
-
- /**
- * Return the codebase URI as a string.
- *
- * @return the codebase uri specification
- */
- public String getCodeBaseURISpec()
- {
- return m_codebase.toASCIIString();
- }
-
- /**
- * Return the array of codebase parameter values.
- *
- * @return the parameter value array
- */
- public ValueDirective[] getValueDirectives()
- {
- return m_parameters;
- }
-
- /**
- * Test if the supplied object is equal to this object.
- * @param other the object to evaluate
- * @return true if this object is equal to the supplied object
- */
- public boolean equals( Object other )
- {
- if( super.equals( other ) && ( other instanceof CodeBaseDirective ) )
- {
- CodeBaseDirective directive = (CodeBaseDirective) other;
- if( !Arrays.equals( m_parameters, directive.m_parameters ) )
- {
- return false;
- }
- else
- {
- return equals( m_codebase, directive.m_codebase );
- }
- }
- else
- {
- return false;
- }
- }
-
- /**
- * Compute the instance hashcode value.
- * @return the hashcode
- */
- public int hashCode()
- {
- int hash = super.hashCode();
- hash ^= hashValue( m_codebase );
- hash ^= hashArray( m_parameters );
- return hash;
- }
-
-}

Added: trunk/main/transit/core/src/main/dpml/transit/info/DTD.java
===================================================================
--- trunk/main/transit/core/src/main/net/dpml/transit/info/DTD.java
2007-01-10 20:29:19 UTC (rev 1810)
+++ trunk/main/transit/core/src/main/dpml/transit/info/DTD.java 2007-02-08
23:42:59 UTC (rev 1833)
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2006-2007 Stephen J. McConnell.
+ *
+ * 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 dpml.transit.info;
+
+import java.net.URI;
+
+/**
+ * DTD reference.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+class DTD
+{
+ /**
+ * Public identifier.
+ */
+ private final String m_public;
+
+ /**
+ * The system identifier.
+ */
+ private final String m_system;
+
+ /**
+ * Local resource.
+ */
+ private final String m_resource;
+
+ /**
+ * Factory uri.
+ */
+ private final URI m_factory;
+
+ public DTD( final String publicId, final String systemId, final String
resource, URI factory )
+ {
+ m_public = publicId;
+ m_system = systemId;
+ m_resource = resource;
+ m_factory = factory;
+ }
+
+ public String getPublicId()
+ {
+ return m_public;
+ }
+
+ public String getSystemId()
+ {
+ return m_system;
+ }
+
+ public String getResource()
+ {
+ return m_resource;
+ }
+
+ public URI getFactory()
+ {
+ return m_factory;
+ }
+}

Added: trunk/main/transit/core/src/main/dpml/transit/info/DTDResolver.java
===================================================================
--- trunk/main/transit/core/src/main/net/dpml/transit/info/DTDResolver.java
2007-01-10 20:29:19 UTC (rev 1810)
+++ trunk/main/transit/core/src/main/dpml/transit/info/DTDResolver.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2004-2007 Stephen J. McConnell.
+ *
+ * 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 dpml.transit.info;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import net.dpml.transit.TransitError;
+
+
+/**
+ * A Class to help to resolve Entitys for items such as DTDs or
+ * Schemas.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+class DTDResolver implements EntityResolver
+{
+ /**
+ * The list of DTDs that can be resolved by this class.
+ */
+ private final DTD[] m_dtds;
+
+ /**
+ * The ClassLoader to use when loading resources for DTDs.
+ */
+ private final ClassLoader m_classloader;
+
+ /**
+ * Construct a resolver using specified DTDInfos where resources are
loaded
+ * from specified ClassLoader.
+ */
+ public DTDResolver( final DTD[] dtds, final ClassLoader classLoader )
+ {
+ m_dtds = dtds;
+ m_classloader = classLoader;
+ }
+
+ /**
+ * Resolve an entity in the XML file.
+ * Called by parser to resolve DTDs.
+ */
+ public InputSource resolveEntity( final String publicId, final String
systemId )
+ throws IOException, SAXException
+ {
+ for( int i=0; i<m_dtds.length; i++ )
+ {
+ final DTD info = m_dtds[i];
+
+ if( ( publicId != null && publicId.equals( info.getPublicId() )
)
+ || ( systemId != null && systemId.equals( info.getSystemId()
) ) )
+ {
+ final String path = info.getResource();
+ final InputStream inputStream = resolveInputStream( path );
+ if( null == inputStream )
+ {
+ final String error =
+ "Matched DTD identifier returned an unresolvable
resource path."
+ + "\nPublic ID: " + info.getPublicId()
+ + "\nSystem ID: " + info.getSystemId()
+ + "\nResource: '" + path + "'";
+ throw new TransitError( error );
+ }
+ else
+ {
+ return new InputSource( inputStream );
+ }
+ }
+ }
+ return null;
+ }
+
+ private InputStream resolveInputStream( String path )
+ {
+ InputStream input =
ClassLoader.getSystemClassLoader().getResourceAsStream( path );
+ if( null != input )
+ {
+ return input;
+ }
+ ClassLoader context = Thread.currentThread().getContextClassLoader();
+ if( null != context )
+ {
+ input = context.getResourceAsStream( path );
+ if( null != input )
+ {
+ return input;
+ }
+ }
+ if( null != m_classloader )
+ {
+ input = m_classloader.getResourceAsStream( path );
+ if( null != input )
+ {
+ return input;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return CLassLoader to load resource from.
+ * If a ClassLoader is specified in the constructor use that,
+ * else use ContextClassLoader unless that is null in which case
+ * use the current classes ClassLoader.
+ */
+ private ClassLoader getClassLoader()
+ {
+ ClassLoader classLoader = m_classloader;
+ if( null == classLoader )
+ {
+ classLoader = Thread.currentThread().getContextClassLoader();
+ }
+ if( null == classLoader )
+ {
+ classLoader = getClass().getClassLoader();
+ }
+ return classLoader;
+ }
+}

Modified:
trunk/main/transit/core/src/main/dpml/transit/info/HostDirective.java
===================================================================
--- trunk/main/transit/core/src/main/net/dpml/transit/info/HostDirective.java
2007-01-10 20:29:19 UTC (rev 1810)
+++ trunk/main/transit/core/src/main/dpml/transit/info/HostDirective.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -16,17 +16,19 @@
* limitations under the License.
*/

-package net.dpml.transit.info;
+package dpml.transit.info;

-import net.dpml.lang.AbstractDirective;
+import java.io.Serializable;

+import dpml.util.ObjectUtils;
+
/**
* Description of a host configuration within Transit.
*
* @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
* @version @PROJECT-VERSION@
*/
-public class HostDirective extends AbstractDirective
+public class HostDirective implements Serializable
{
private final String m_id;
private final int m_priority;
@@ -209,10 +211,10 @@
*/
public boolean equals( Object other )
{
- if( super.equals( other ) && ( other instanceof HostDirective ) )
+ if( other instanceof HostDirective )
{
HostDirective directive = (HostDirective) other;
- if( !equals( m_id, directive.m_id ) )
+ if( !ObjectUtils.equals( m_id, directive.m_id ) )
{
return false;
}
@@ -228,27 +230,27 @@
{
return false;
}
- else if( !equals( m_host, directive.m_host ) )
+ else if( !ObjectUtils.equals( m_host, directive.m_host ) )
{
return false;
}
- else if( !equals( m_index, directive.m_index ) )
+ else if( !ObjectUtils.equals( m_index, directive.m_index ) )
{
return false;
}
- else if( !equals( m_username, directive.m_username ) )
+ else if( !ObjectUtils.equals( m_username, directive.m_username )
)
{
return false;
}
- else if( !equals( m_layout, directive.m_layout ) )
+ else if( !ObjectUtils.equals( m_layout, directive.m_layout ) )
{
return false;
}
- else if( !equals( m_scheme, directive.m_scheme ) )
+ else if( !ObjectUtils.equals( m_scheme, directive.m_scheme ) )
{
return false;
}
- else if( !equals( m_prompt, directive.m_prompt ) )
+ else if( !ObjectUtils.equals( m_prompt, directive.m_prompt ) )
{
return false;
}
@@ -284,19 +286,19 @@
public int hashCode()
{
int hash = m_priority;
- hash ^= hashValue( m_id );
- hash ^= hashValue( new Boolean( m_trusted ) );
- hash ^= hashValue( new Boolean( m_enabled ) );
- hash ^= hashValue( m_host );
- hash ^= hashValue( m_index );
- hash ^= hashValue( m_username );
+ hash ^= ObjectUtils.hashValue( m_id );
+ hash ^= ObjectUtils.hashValue( new Boolean( m_trusted ) );
+ hash ^= ObjectUtils.hashValue( new Boolean( m_enabled ) );
+ hash ^= ObjectUtils.hashValue( m_host );
+ hash ^= ObjectUtils.hashValue( m_index );
+ hash ^= ObjectUtils.hashValue( m_username );
if( null != m_password )
{
hash ^= new String( m_password ).hashCode();
}
- hash ^= hashValue( m_layout );
- hash ^= hashValue( m_scheme );
- hash ^= hashValue( m_prompt );
+ hash ^= ObjectUtils.hashValue( m_layout );
+ hash ^= ObjectUtils.hashValue( m_scheme );
+ hash ^= ObjectUtils.hashValue( m_prompt );
return hash;
}


Deleted:
trunk/main/transit/core/src/main/dpml/transit/info/LayoutDirective.java
===================================================================
---
trunk/main/transit/core/src/main/net/dpml/transit/info/LayoutDirective.java
2007-01-10 20:29:19 UTC (rev 1810)
+++ trunk/main/transit/core/src/main/dpml/transit/info/LayoutDirective.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -1,121 +0,0 @@
-/*
- * Copyright 2005 Stephen J. McConnell.
- *
- * 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 net.dpml.transit.info;
-
-import java.net.URI;
-
-import net.dpml.lang.ValueDirective;
-
-/**
- * The CodeBaseDirective is immutable datastructure used to
- * describe a codebase.
- *
- * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
- * @version @PROJECT-VERSION@
- */
-public class LayoutDirective extends CodeBaseDirective
-{
- private final String m_id;
- private final String m_title;
-
- /**
- * Creation of a new codebase descriptor.
- * @param id the datatype identifier
- * @param title the handler title
- * @param codebase the codebase uri
- * @param parameters an array of plugin parameter descriptors
- * @exception NullPointerException if the id is null
- */
- public LayoutDirective(
- String id, String title, URI codebase, ValueDirective[] parameters )
- throws NullPointerException
- {
- super( codebase, parameters );
- if( null == id )
- {
- throw new NullPointerException( "id" );
- }
- m_id = id;
- if( null == title )
- {
- m_title = id;
- }
- else
- {
- m_title = title;
- }
- }
-
- /**
- * Return the unique content handler datatype identifier.
- *
- * @return the handler id
- */
- public String getID()
- {
- return m_id;
- }
-
- /**
- * Return the content handler title.
- *
- * @return the title
- */
- public String getTitle()
- {
- return m_title;
- }
-
- /**
- * Test if the supplied object is equal to this object.
- * @param other the object to evaluate
- * @return true if this object is equal to the supplied object
- */
- public boolean equals( Object other )
- {
- if( super.equals( other ) && ( other instanceof LayoutDirective ) )
- {
- LayoutDirective directive = (LayoutDirective) other;
- if( !equals( m_id, directive.m_id ) )
- {
- return false;
- }
- else
- {
- return equals( m_title, directive.m_title );
- }
- }
- else
- {
- return false;
- }
- }
-
- /**
- * Compute the instance hashcode value.
- * @return the hashcode
- */
- public int hashCode()
- {
- int hash = super.hashCode();
- hash ^= hashValue( m_id );
- hash ^= hashValue( m_title );
- return hash;
- }
-}

Modified:
trunk/main/transit/core/src/main/dpml/transit/info/ProxyDirective.java
===================================================================
---
trunk/main/transit/core/src/main/net/dpml/transit/info/ProxyDirective.java
2007-01-10 20:29:19 UTC (rev 1810)
+++ trunk/main/transit/core/src/main/dpml/transit/info/ProxyDirective.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -16,11 +16,12 @@
* limitations under the License.
*/

-package net.dpml.transit.info;
+package dpml.transit.info;

import java.util.Arrays;
+import java.io.Serializable;

-import net.dpml.lang.AbstractDirective;
+import dpml.util.ObjectUtils;

/**
* Description of the proxy configuration of a Transit system.
@@ -28,7 +29,7 @@
* @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
* @version @PROJECT-VERSION@
*/
-public class ProxyDirective extends AbstractDirective
+public class ProxyDirective implements Serializable
{
private final String m_host;
private final String m_username;
@@ -100,10 +101,10 @@
*/
public boolean equals( Object other )
{
- if( super.equals( other ) && ( other instanceof ProxyDirective ) )
+ if( other instanceof ProxyDirective )
{
ProxyDirective directive = (ProxyDirective) other;
- if( !equals( m_host, directive.m_host ) )
+ if( !ObjectUtils.equals( m_host, directive.m_host ) )
{
return false;
}
@@ -111,7 +112,7 @@
{
return false;
}
- else if( !equals( m_username, directive.m_username ) )
+ else if( !ObjectUtils.equals( m_username, directive.m_username )
)
{
return false;
}
@@ -147,11 +148,11 @@
public int hashCode()
{
int hash = 0;
- hash ^= hashValue( m_host );
- hash ^= hashArray( m_excludes );
+ hash ^= ObjectUtils.hashValue( m_host );
+ hash ^= ObjectUtils.hashArray( m_excludes );
if( null != m_password )
{
- hash ^= hashValue( m_username );
+ hash ^= ObjectUtils.hashValue( m_username );
}
if( null != m_password )
{

Added: trunk/main/transit/core/src/main/dpml/transit/info/SaxMonitor.java
===================================================================
--- trunk/main/transit/core/src/main/net/dpml/transit/info/SaxMonitor.java
2007-01-10 20:29:19 UTC (rev 1810)
+++ trunk/main/transit/core/src/main/dpml/transit/info/SaxMonitor.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2006-2007 Stephen J. McConnell.
+ *
+ * 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 dpml.transit.info;
+
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+import net.dpml.util.Logger;
+
+/**
+ * Utility class supporting the reading and writing of standard plugins
definitions.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+final class SaxMonitor implements ErrorHandler
+{
+ private Logger m_logger;
+
+ public SaxMonitor( Logger logger )
+ {
+ if( null == logger )
+ {
+ throw new NullPointerException( "logger" );
+ }
+ m_logger = logger;
+ }
+
+ public void error( SAXParseException e ) throws SAXException
+ {
+ final String message = getMessage( e );
+ m_logger.warn( message );
+ }
+
+ public void fatalError( SAXParseException e ) throws SAXException
+ {
+ final String message = getMessage( e );
+ m_logger.error( message );
+ }
+
+ public void warning( SAXParseException e ) throws SAXException
+ {
+ final String message = getMessage( e );
+ m_logger.warn( message );
+ }
+
+ private String getMessage( SAXParseException e )
+ {
+ return e.getMessage()
+ + "(" + e.getLineNumber()
+ + "," + e.getColumnNumber()
+ + ")";
+ }
+}

Added: trunk/main/transit/core/src/main/dpml/transit/info/TransitDecoder.java
===================================================================
---
trunk/main/transit/core/src/main/net/dpml/transit/info/TransitDecoder.java
2007-01-10 20:29:19 UTC (rev 1810)
+++ trunk/main/transit/core/src/main/dpml/transit/info/TransitDecoder.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,264 @@
+/*
+ * Copyright 2006-2007 Stephen J. McConnell.
+ *
+ * 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 dpml.transit.info;
+
+import dpml.util.ElementHelper;
+
+import java.net.URL;
+import java.net.URLConnection;
+import java.io.InputStream;
+import java.io.IOException;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import net.dpml.transit.TransitError;
+
+import net.dpml.util.Logger;
+
+import org.xml.sax.ErrorHandler;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.Document;
+
+/**
+ * Utility class supporting the reading of Transit XML configurations.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+class TransitDecoder
+{
+ private static final String XML_HEADER =
+ "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>";
+
+ private static final String NAME = "transit";
+
+ private static final String PUBLIC_ID =
+ "-//DPML//DTD Transit Configuration Version 2.0//EN";
+
+ private static final String SYSTEM_ID =
+ "http://download.dpml.net/dtds/transit_2_0.dtd";;
+
+ private static final String RESOURCE =
+ "net/dpml/transit/transit_2_0.dtd";
+
+ private static final String DOCTYPE =
+ "\n<!DOCTYPE "
+ + NAME
+ + " PUBLIC \""
+ + PUBLIC_ID
+ + "\" \""
+ + SYSTEM_ID
+ + "\" >";
+
+ private static final DTD[] DTDS = new DTD[]
+ {
+ new DTD(
+ "-//DPML//DTD Transit Configuration Version 2.0//EN",
+ "http://download.dpml.net/dtds/transit_2_0.dtd";,
+ "net/dpml/transit/transit_2_0.dtd", null ),
+ new DTD(
+ "-//DPML//DTD Transit Configuration Version 1.0//EN",
+ "http://download.dpml.net/dtds/transit_1_0.dtd";,
+ "net/dpml/transit/transit_1_0.dtd", null )
+ };
+
+ private Logger m_logger;
+
+ /**
+ * Creation of a new transit configuration builder.
+ * @param logger the assigned logging channel
+ */
+ public TransitDecoder( Logger logger )
+ {
+ m_logger = logger;
+ }
+
+ /**
+ * Construct a transit configuration from a supplied uri.
+ * @param url the configuration url
+ * @return the transit configuration
+ * @exception Exception if an error occurs during configuration loading
+ */
+ public TransitDirective decode( final URL url ) throws IOException
+ {
+ try
+ {
+ URLConnection connection = url.openConnection();
+ InputStream input = connection.getInputStream();
+
+ final DocumentBuilderFactory factory =
+ DocumentBuilderFactory.newInstance();
+ factory.setValidating( true );
+ factory.setNamespaceAware( true );
+ factory.setExpandEntityReferences( true );
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ DTDResolver resolver =
+ new DTDResolver( DTDS, getClass().getClassLoader() );
+ builder.setEntityResolver( resolver );
+ ErrorHandler errors = new SaxMonitor( m_logger );
+ builder.setErrorHandler( errors );
+
+ final Document document = builder.parse( input );
+ final Element root = document.getDocumentElement();
+ return build( root );
+ }
+ catch( IOException ioe )
+ {
+ throw ioe;
+ }
+ catch( Exception e )
+ {
+ final String error =
+ "Unexpected error while attempting to decode transit
configuration: "
+ + url;
+ throw new TransitError( error );
+ }
+ }
+
+ //-------------------------------------------------------------
+ // internals supporting XML to directive transformation
+ //-------------------------------------------------------------
+
+ private TransitDirective build( Element root ) throws IOException
+ {
+ String name = root.getTagName();
+ if( !NAME.equals( name ) )
+ {
+ final String error =
+ "Invalid root element name ["
+ + name
+ + "].";
+ throw new IOException( error );
+ }
+
+ String cachePath = ElementHelper.getAttribute( root, "cache" );
+ String cacheLayout = ElementHelper.getAttribute( root, "layout" );
+ Element localElement = ElementHelper.getChild( root, "local" );
+ String localPath = ElementHelper.getAttribute( localElement, "path"
);
+ String localLayout = ElementHelper.getAttribute( localElement,
"layout" );
+ Element proxyElement = ElementHelper.getChild( root, "proxy" );
+ ProxyDirective proxy = buildProxyDirective( proxyElement );
+ Element hostsElement = ElementHelper.getChild( root, "hosts" );
+ Element contentElement = ElementHelper.getChild( root, "content" );
+ HostDirective[] hosts = buildHosts( hostsElement );
+
+ CacheDirective cache =
+ new CacheDirective(
+ cachePath, cacheLayout, localPath, localLayout, hosts );
+
+ return new TransitDirective( proxy, cache );
+ }
+
+ private ProxyDirective buildProxyDirective( Element element )
+ {
+ if( null == element )
+ {
+ return null;
+ }
+ else
+ {
+ String host = ElementHelper.getAttribute( element, "host" );
+ Element credentialsElement = ElementHelper.getChild( element,
"credentials" );
+ String username = getUsername( credentialsElement );
+ char[] password = getPassword( credentialsElement );
+ String[] excludes = buildProxyExcludes( element );
+ return new ProxyDirective( host, excludes, username, password );
+ }
+ }
+
+ private String[] buildProxyExcludes( Element element )
+ {
+ if( null == element )
+ {
+ return null;
+ }
+ else
+ {
+ Element[] elements = ElementHelper.getChildren( element,
"exclude" );
+ String[] excludes = new String[ elements.length ];
+ for( int i=0; i<excludes.length; i++ )
+ {
+ Element elem = elements[i];
+ excludes[i] = ElementHelper.getValue( elem );
+ }
+ return excludes;
+ }
+ }
+
+ private HostDirective[] buildHosts( Element element )
+ {
+ Element[] elements = ElementHelper.getChildren( element, "host" );
+ HostDirective[] hosts = new HostDirective[ elements.length ];
+ for( int i=0; i<hosts.length; i++ )
+ {
+ Element elem = elements[i];
+ String id = ElementHelper.getAttribute( elem, "id" );
+ int priority = Integer.parseInt( ElementHelper.getAttribute(
elem, "priority" ) );
+ String url = ElementHelper.getAttribute( elem, "url" );
+ String layout = ElementHelper.getAttribute( elem, "layout" );
+ boolean enabled = ElementHelper.getBooleanAttribute( elem,
"enabled" );
+ boolean trusted = ElementHelper.getBooleanAttribute( elem,
"trusted" );
+ String index = ElementHelper.getAttribute( elem, "index" );
+ String scheme = ElementHelper.getAttribute( elem, "scheme" );
+ String prompt = ElementHelper.getAttribute( elem, "prompt" );
+ Element credentialsElement = ElementHelper.getChild( elem,
"credentials" );
+ String username = getUsername( credentialsElement );
+ char[] password = getPassword( credentialsElement );
+ hosts[i] =
+ new HostDirective(
+ id, priority, url, index, username, password, enabled,
trusted,
+ layout, scheme, prompt );
+ }
+ return hosts;
+ }
+
+ private String getUsername( Element element )
+ {
+ if( null == element )
+ {
+ return null;
+ }
+ else
+ {
+ return ElementHelper.getAttribute( element, "username" );
+ }
+ }
+
+ private char[] getPassword( Element element )
+ {
+ if( null == element )
+ {
+ return null;
+ }
+ else
+ {
+ String password = ElementHelper.getAttribute( element,
"password" );
+ if( null == password )
+ {
+ return null;
+ }
+ else
+ {
+ return password.toCharArray();
+ }
+ }
+ }
+}

Modified:
trunk/main/transit/core/src/main/dpml/transit/info/TransitDirective.java
===================================================================
---
trunk/main/transit/core/src/main/net/dpml/transit/info/TransitDirective.java
2007-01-10 20:29:19 UTC (rev 1810)
+++ trunk/main/transit/core/src/main/dpml/transit/info/TransitDirective.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -16,10 +16,18 @@
* limitations under the License.
*/

-package net.dpml.transit.info;
+package dpml.transit.info;

-import net.dpml.lang.AbstractDirective;
+import dpml.util.ObjectUtils;
+import dpml.util.DefaultLogger;

+import java.io.Serializable;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URL;
+
+import net.dpml.util.Logger;
+
/**
* The CodeBaseDirective is immutable datastructure used to
* describe a codebase.
@@ -27,13 +35,43 @@
* @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
* @version @PROJECT-VERSION@
*/
-public class TransitDirective extends AbstractDirective
+public class TransitDirective implements Serializable
{
/**
* Classic configuration profile.
*/
public static final TransitDirective CLASSIC_PROFILE =
createClassicProfile();

+ /**
+ * Utility method to load a transit configuration from XML.
+ * @param url the url identifying the configuration source
+ * @return the configuration directive
+ * @exception Exception if an error occurs during configuration loading
+ */
+ public static TransitDirective decode( URL url ) throws IOException
+ {
+ Logger logger = new DefaultLogger( "dpml.transit" );
+ TransitDecoder decoder = new TransitDecoder( logger );
+ return decoder.decode( url );
+ }
+
+ /**
+ * Utility method to save a transit configuration as XML to a given
+ * output stream.
+ * @param directive the transit directive to externalize
+ * @param stream the output stream
+ * @exception Exception if an error occurs
+ */
+ public static void encode(
+ TransitDirective directive, OutputStream stream ) throws IOException
+ {
+ Logger logger = new DefaultLogger( "dpml.transit" );
+ TransitEncoder encoder = new TransitEncoder( logger );
+ encoder.encode( directive, stream );
+ }
+
+
+
private final ProxyDirective m_proxy;
private final CacheDirective m_cache;

@@ -82,16 +120,16 @@
*/
public boolean equals( Object other )
{
- if( super.equals( other ) && ( other instanceof TransitDirective ) )
+ if( other instanceof TransitDirective )
{
TransitDirective directive = (TransitDirective) other;
- if( !equals( m_proxy, directive.m_proxy ) )
+ if( !ObjectUtils.equals( m_proxy, directive.m_proxy ) )
{
return false;
}
else
{
- return equals( m_cache, directive.m_cache );
+ return ObjectUtils.equals( m_cache, directive.m_cache );
}
}
else
@@ -106,9 +144,9 @@
*/
public int hashCode()
{
- int hash = super.hashCode();
- hash ^= hashValue( m_proxy );
- hash ^= hashValue( m_cache );
+ int hash = getClass().hashCode();
+ hash ^= ObjectUtils.hashValue( m_proxy );
+ hash ^= ObjectUtils.hashValue( m_cache );
return hash;
}

@@ -132,15 +170,7 @@
"apache", 140, "http://www.apache.org/dist/java-repository";,
null, null, null,
true, false, "classic", null, null );

- CacheDirective cache =
- new CacheDirective(
- CacheDirective.CACHE_PATH,
- CacheDirective.CACHE_LAYOUT,
- CacheDirective.LOCAL_PATH,
- CacheDirective.LOCAL_LAYOUT,
- CacheDirective.EMPTY_LAYOUTS,
- hosts );
+ CacheDirective cache = new CacheDirective( hosts );
return new TransitDirective( null, cache );
}
-
}

Added: trunk/main/transit/core/src/main/dpml/transit/info/TransitEncoder.java
===================================================================
---
trunk/main/transit/core/src/main/net/dpml/transit/info/TransitEncoder.java
2007-01-10 20:29:19 UTC (rev 1810)
+++ trunk/main/transit/core/src/main/dpml/transit/info/TransitEncoder.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,275 @@
+/*
+ * Copyright 2006-2007 Stephen J. McConnell.
+ *
+ * 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 dpml.transit.info;
+
+import dpml.util.ElementHelper;
+
+import java.net.URL;
+import java.net.URLConnection;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import net.dpml.util.Logger;
+
+import org.xml.sax.ErrorHandler;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.Document;
+
+/**
+ * Utility class supporting the writing of Transit directives to XML.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+class TransitEncoder
+{
+ private static final String XML_HEADER =
+ "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>";
+
+ private static final String NAME = "transit";
+
+ private static final String PUBLIC_ID =
+ "-//DPML//DTD Transit Configuration Version 2.0//EN";
+
+ private static final String SYSTEM_ID =
+ "http://download.dpml.net/dtds/transit_2_0.dtd";;
+
+ private static final String RESOURCE =
+ "net/dpml/transit/transit_2_0.dtd";
+
+ private static final String DOCTYPE =
+ "\n<!DOCTYPE "
+ + NAME
+ + " PUBLIC \""
+ + PUBLIC_ID
+ + "\" \""
+ + SYSTEM_ID
+ + "\" >";
+
+ private Logger m_logger;
+
+ /**
+ * Creation of a new transit configuration builder.
+ * @param logger the assigned logging channel
+ */
+ public TransitEncoder( Logger logger )
+ {
+ m_logger = logger;
+ }
+
+ //-------------------------------------------------------------
+ // impl
+ //-------------------------------------------------------------
+
+ /**
+ * Write a transit directive to an output stream as XML.
+ * @param directive the directive to externalize
+ * @param output the output stream to write to
+ * @exception IOException if an I/O error occurs
+ */
+ public void encode( TransitDirective directive, OutputStream output )
throws IOException
+ {
+ final Writer writer = new OutputStreamWriter( output );
+ try
+ {
+ writer.write( XML_HEADER );
+ writer.write( DOCTYPE );
+
+ CacheDirective cache = directive.getCacheDirective();
+ String cachePath = cache.getCache();
+ String cacheLayout = cache.getCacheLayout();
+ writeHeader( writer, cachePath, cacheLayout );
+
+ ProxyDirective proxy = directive.getProxyDirective();
+ writeProxy( writer, proxy );
+
+ String localPath = cache.getLocal();
+ String localLayout = cache.getLocalLayout();
+ writeLocal( writer, localPath, localLayout );
+
+ HostDirective[] hosts = cache.getHostDirectives();
+ writeHosts( writer, hosts );
+
+ writeFooter( writer );
+ writer.write( "\n" );
+ }
+ finally
+ {
+ writer.flush();
+ writer.close();
+ }
+ }
+
+ private void writeHeader( Writer writer, String cache, String layout )
throws IOException
+ {
+ writer.write( "\n\n<" + NAME + " cache=\"" + cache + "\" layout=\""
+ layout + "\">" );
+ }
+
+ private void writeFooter( Writer writer ) throws IOException
+ {
+ writer.write( "\n</" + NAME + ">" );
+ }
+
+ private void writeProxy( Writer writer, ProxyDirective proxy ) throws
IOException
+ {
+ if( null != proxy )
+ {
+ String host = proxy.getHost();
+ String username = proxy.getUsername();
+ String password = getPassword( proxy.getPassword() );
+ String[] excludes = proxy.getExcludes();
+
+ boolean credentials = ( ( null != username ) || ( null !=
password ) );
+
+ if( excludes.length == 0 && ( !credentials ) )
+ {
+ writer.write(
+ "\n <proxy host=\"" + host + "\"/>" );
+ }
+ else
+ {
+ writer.write( "\n <proxy host=\"" + host + "\">" );
+ if( credentials )
+ {
+ writer.write( "\n <credentials" );
+ if( null != username )
+ {
+ writer.write( " username=\"" + username + "\"" );
+ }
+ if( null != password )
+ {
+ writer.write( " password=\"" + password + "\"" );
+ }
+ writer.write( "/>" );
+ }
+ if( excludes.length > 0 )
+ {
+ writer.write( "\n <excludes>" );
+ for( int i=0; i<excludes.length; i++ )
+ {
+ String exclude = excludes[i];
+ writer.write( "\n <exclude>" + exclude +
"</exclude>" );
+ }
+ writer.write( "\n </excludes>" );
+ }
+
+ writer.write( "\n </proxy>" );
+ }
+ }
+ }
+
+ private void writeLocal( Writer writer, String path, String layout )
throws IOException
+ {
+ writer.write( "\n <local path=\"" + path + "\" layout=\"" + layout
+ "\"/>" );
+ }
+
+ private void writeHosts( Writer writer, HostDirective[] hosts ) throws
IOException
+ {
+ writer.write( "\n <hosts>" );
+ for( int i=0; i<hosts.length; i++ )
+ {
+ HostDirective host = hosts[i];
+ writeHost( writer, host );
+ }
+ writer.write( "\n </hosts>" );
+ }
+
+ private void writeHost( Writer writer, HostDirective host ) throws
IOException
+ {
+ String id = host.getID();
+ int priority = host.getPriority();
+ String url = host.getHost();
+ boolean enabled = host.getEnabled();
+ boolean trusted = host.getTrusted();
+ String layout = host.getLayout();
+ String index = host.getIndex();
+ String scheme = host.getScheme();
+ String prompt = host.getPrompt();
+ String username = host.getUsername();
+ String password = getPassword( host.getPassword() );
+ boolean credentials = ( ( null != username ) || ( null != password )
);
+
+ writer.write(
+ "\n <host id=\"" + id
+ + "\" priority=\"" + priority
+ + "\" url=\"" + url
+ + "\"" );
+ if( !enabled )
+ {
+ writer.write( " enabled=\"false\"" );
+ }
+ if( trusted )
+ {
+ writer.write( " trusted=\"true\"" );
+ }
+ if( null != layout )
+ {
+ writer.write( " layout=\"" + layout + "\"" );
+ }
+ if( null != index )
+ {
+ writer.write( " index=\"" + index + "\"" );
+ }
+ if( ( null != scheme ) && !scheme.equals( "" ) )
+ {
+ writer.write( " scheme=\"" + scheme + "\"" );
+ }
+ if( ( null != prompt ) && !prompt.equals( "" ) )
+ {
+ writer.write( " prompt=\"" + prompt + "\"" );
+ }
+ if( credentials )
+ {
+ writer.write( "\n <credentials" );
+ if( null != username )
+ {
+ writer.write( " username=\"" + username + "\"" );
+ }
+ if( null != password )
+ {
+ writer.write( " password=\"" + password + "\"" );
+ }
+ writer.write( "/>" );
+ writer.write( "\n </host>" );
+ }
+ else
+ {
+ writer.write( "/>" );
+ }
+ }
+
+ private String getPassword( char[] password )
+ {
+ if( null == password )
+ {
+ return null;
+ }
+ else
+ {
+ return new String( password );
+ }
+ }
+}

Added: trunk/main/transit/core/src/main/dpml/transit/info/package-info.java
===================================================================
--- trunk/main/transit/core/src/main/net/dpml/transit/info/package-info.java
2007-01-10 20:29:19 UTC (rev 1810)
+++ trunk/main/transit/core/src/main/dpml/transit/info/package-info.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2004-2006 Stephen J. McConnell.
+ *
+ * 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.
+ */
+
+/**
+ * <p>Immutable datastructures reflecting a transit configuration. The
+ * principal class {@link dpml.transit.info.TransitDirective} holds
+ * a single {@link dpml.transit.info.CacheDirective} and optional
+ * {@link dpml.transit.info.ProxyDirective}. The {@link
dpml.transit.info.CacheDirective}
+ * holds 0..n {@link dpml.transit.info.HostDirective} values.
+ * Collectively these descriptors define the Transit deployment
configuration.
+ * An instance of {@code TransitDirective} is supplied as an argument to
+ * {@link net.dpml.transit.Transit} via the system property
+ * {@code dpml.transit.profile} as a part of the
+ * {@link net.dpml.transit.Transit#getInstance()} invocation (typically
+ * invoked by Transit subsystems when handling URL resolution).</p>
+ *
+ * <P><img src="doc-files/transit-directive-uml.png"/></P>
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+package dpml.transit.info;

Deleted: trunk/main/transit/core/src/main/dpml/transit/info/package.html
===================================================================
--- trunk/main/transit/core/src/main/net/dpml/transit/info/package.html
2007-01-10 20:29:19 UTC (rev 1810)
+++ trunk/main/transit/core/src/main/dpml/transit/info/package.html
2007-02-08 23:42:59 UTC (rev 1833)
@@ -1,7 +0,0 @@
-
-<body>
-<p>
-Data structures supporting long term persistence of transit systems
configuration.
-</p>
-</body>
-

Copied: trunk/main/transit/core/src/main/dpml/transit/link (from rev 1810,
trunk/main/transit/core/src/main/net/dpml/transit/link)

Deleted:
trunk/main/transit/core/src/main/dpml/transit/link/ArtifactLinkManager.java
===================================================================
---
trunk/main/transit/core/src/main/net/dpml/transit/link/ArtifactLinkManager.java
2007-01-10 20:29:19 UTC (rev 1810)
+++
trunk/main/transit/core/src/main/dpml/transit/link/ArtifactLinkManager.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -1,170 +0,0 @@
-/*
- * Copyright 2005 Niclas Hedhman
- * Copyright 2005 Stephen J. McConnell.
- *
- * 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 net.dpml.transit.link;
-
-import net.dpml.util.StreamUtils;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.URI;
-import java.net.URL;
-import java.security.AccessController;
-import java.security.PrivilegedActionException;
-import java.security.PrivilegedExceptionAction;
-
-import net.dpml.transit.Artifact;
-import net.dpml.transit.NullArgumentException;
-import net.dpml.transit.artifact.ArtifactNotFoundException;
-import net.dpml.util.PropertyResolver;
-
-/**
- * A link manager that maintains persistent link information as a resource.
- * Link resource located using the
[cache]/[group]/[name]/[type]s/[name]-[version].[type].link
- * resource naming convention.
- *
- * Applications should not call the methods for the LinkManager directly,
- * and it is likely that the LinkManager remains outside the reachability of
- * applications.
- * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
- * @version @PROJECT-VERSION@
- */
-public class ArtifactLinkManager
- implements LinkManager
-{
- /**
- * Sets the URI for the provided Link.
- * The LinkManager is required to persist this information between
- * JVM restarts and should be persisted on a scope larger than a
- * single JVM, typically a host or a local area network. LinkManagers
- * are encouraged to establish other virtual scopes independent of
- * network topologies.
- *
- * @param linkUri the uri of the link resource
- * @param targetUri the uri that the link redirects to
- * @exception IOException if the mapping could not be updated.
- */
- public void setTargetURI( final URI linkUri, final URI targetUri )
- throws IOException
- {
- if( null == linkUri )
- {
- throw new NullArgumentException( "linkUri" );
- }
-
- try
- {
- AccessController.doPrivileged(
- new PrivilegedExceptionAction()
- {
- public Object run()
- throws IOException
- {
- String artifact = linkUri.toASCIIString();
- URL store = new URL( null, artifact, new
net.dpml.transit.artifact.Handler() );
- OutputStream out =
store.openConnection().getOutputStream();
- byte[] array = getByteArray( targetUri );
- ByteArrayInputStream in = new ByteArrayInputStream(
array );
- StreamUtils.copyStream( in, out, true );
- return null; // nothing to return
- }
- }
- );
- }
- catch( PrivilegedActionException e )
- {
- throw (IOException) e.getException();
- }
- }
-
- /**
- * Returns the URI that the provided link URI instance is pointing to.
- * @param linkUri the link uri from which the target will be resolved
- * @exception LinkNotFoundException if the supplied link uri could not
be located
- * @exception IOException if the mapping could not be retrieved, due to
- * an IOException during link retrival.
- * @return target URI that the link points to (possibly null if the link
does
- * not declare a target)
- */
- public URI getTargetURI( final URI linkUri )
- throws IOException, LinkNotFoundException
- {
- try
- {
- URI result = (URI) AccessController.doPrivileged(
- new PrivilegedExceptionAction()
- {
- public Object run()
- throws IOException
- {
- URL store = null;
- if( Artifact.isRecognized( linkUri ) )
- {
- String artifact = linkUri.toASCIIString();
- store = new URL( null, artifact, new
net.dpml.transit.artifact.Handler() );
- }
- else
- {
- store = linkUri.toURL();
- }
-
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- InputStream in = store.openConnection().getInputStream();
- StreamUtils.copyStream( in, out, true );
- String target = out.toString( "ISO8859-1" );
- String path = PropertyResolver.resolve( target );
- URI value = URI.create( path );
- return value;
- }
- }
- );
- return result;
- }
- catch( PrivilegedActionException e )
- {
- Exception exception = e.getException();
- if( exception instanceof ArtifactNotFoundException )
- {
- final String error =
- "Link not found: "
- + linkUri;
- throw new LinkNotFoundException( error, linkUri );
- }
- else
- {
- throw (IOException) exception;
- }
- }
- }
-
- private byte[] getByteArray( URI uri ) throws IOException
- {
- if( null != uri )
- {
- return uri.toString().getBytes( "ISO8859-1" );
- }
- else
- {
- return new byte[0];
- }
- }
-}

Modified: trunk/main/transit/core/src/main/dpml/transit/link/Handler.java
===================================================================
--- trunk/main/transit/core/src/main/net/dpml/transit/link/Handler.java
2007-01-10 20:29:19 UTC (rev 1810)
+++ trunk/main/transit/core/src/main/dpml/transit/link/Handler.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -1,6 +1,5 @@
/*
- * Copyright 2005 Niclas Hedhman
- * Copyright 2005-2006 Stephen J. McConnell
+ * Copyright 2007 Stephen J. McConnell
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,10 +16,9 @@
* limitations under the License.
*/

-package net.dpml.transit.link;
+package dpml.transit.link;

import java.io.IOException;
-
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;

Deleted: trunk/main/transit/core/src/main/dpml/transit/link/Link.java
===================================================================
--- trunk/main/transit/core/src/main/net/dpml/transit/link/Link.java
2007-01-10 20:29:19 UTC (rev 1810)
+++ trunk/main/transit/core/src/main/dpml/transit/link/Link.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -1,115 +0,0 @@
-/*
- * Copyright 2005 Niclas Hedhman
- * Copyright 2005 Stephen McConnell
- *
- * 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 net.dpml.transit.link;
-
-import java.io.IOException;
-
-import java.net.URI;
-
-import net.dpml.transit.NullArgumentException;
-
-/**
- * The Link class is a data structure that holds the target uri of a link.
- *
- * It is not intended that the applications instantiates this class
directly,
- * but obtains it as a object from the <code>URL.getContent()</code> method.
- * Example;
- *
- * <pre><code>
- * URL url = new URL( "link:jar:some/opague/pointer" );
- * Class[] type = new Class[] { Link.class };
- *
- * // Get the Link object from the URL
- * Link link = (Link) url.getContent( type );
- *
- * // Get the URI that this link is pointing to at the moment
- * URI uri = link.getTargetURI();
- *
- * // Change the link to point somewhere else.
- * URI newUri = new URI( "artifact:jar:abc/def/hoopla#3.1.2" );
- * link.setTargetURI( newUri );
- * </code></pre>
- * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
- * @version @PROJECT-VERSION@
- */
-public class Link
-{
- private final LinkManager m_manager;
- private final URI m_uri;
-
- /**
- * Constructor for the Link.
- * @param uri the link physical uri
- * @param manager the link manager
- * @exception NullArgumentException if the link uri or manager is null
- */
- public Link( URI uri, LinkManager manager ) throws NullArgumentException
- {
- if( null == manager )
- {
- throw new NullArgumentException( "manager" );
- }
- if( null == uri )
- {
- throw new NullArgumentException( "uri" );
- }
-
- m_manager = manager;
- m_uri = uri;
- }
-
- /**
- * Return the link uri.
- * @return the link uri value
- */
- public URI getLinkURI()
- {
- return m_uri;
- }
-
- /**
- * Return the URI that is currently bound to the Link.
- * @param defaultUri the default value
- * @return the current URI the link: is pointing to.
- * @exception IOException if an IO error occurs
- */
- public URI getTargetURI( URI defaultUri ) throws IOException
- {
- try
- {
- return m_manager.getTargetURI( m_uri );
- }
- catch( LinkNotFoundException e )
- {
- return defaultUri;
- }
- }
-
- /**
- * Sets (and permanently remembers) the Link to point to a new URI.
- * @param uri the URI that this link: should be pointing to.
- * @exception IOException if an IO error occurs
- */
- public void setTargetURI( URI uri ) throws IOException
- {
- m_manager.setTargetURI( m_uri, uri );
- }
-}
-

Deleted: trunk/main/transit/core/src/main/dpml/transit/link/LinkManager.java
===================================================================
--- trunk/main/transit/core/src/main/net/dpml/transit/link/LinkManager.java
2007-01-10 20:29:19 UTC (rev 1810)
+++ trunk/main/transit/core/src/main/dpml/transit/link/LinkManager.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -1,56 +0,0 @@
-/*
- * Copyright 2005 Niclas Hedhman
- * Copyright 2005 Stephen McConnell
- * 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 net.dpml.transit.link;
-
-import java.io.IOException;
-
-import java.net.URI;
-
-/**
- * The LinkManager is responsible for storing the mapping between a Link
- * instance and a URI.
- * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
- * @version @PROJECT-VERSION@
- */
-public interface LinkManager
-{
- /**
- * Sets the URI for the provided link URI.
- * The LinkManager is required to persist this information between
- * JVM restarts and should be persisted on a scope larger than a
- * single JVM, typically a host or a local area network. LinkManagers
- * are encouraged to establish other virtual scopes independent of
- * network topologies.
- *
- * @param link the uri of the link
- * @param target the uri of the target that the link redirects to
- * @exception IOException if an IO error occurs
- */
- void setTargetURI( URI link, URI target ) throws IOException;
-
- /**
- * Returns the URI that the supplied link URI is referencing.
- *
- * @param link the link uri
- * @return the target uri
- * @exception IOException if an IO error occurs
- */
- URI getTargetURI( URI link ) throws IOException;
-
-}

Deleted:
trunk/main/transit/core/src/main/dpml/transit/link/LinkNotFoundException.java
===================================================================
---
trunk/main/transit/core/src/main/net/dpml/transit/link/LinkNotFoundException.java
2007-01-10 20:29:19 UTC (rev 1810)
+++
trunk/main/transit/core/src/main/dpml/transit/link/LinkNotFoundException.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -1,53 +0,0 @@
-/*
- * Copyright 2004-2005 Stephen J. McConnell.
- *
- * 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 net.dpml.transit.link;
-
-import java.net.URI;
-
-import net.dpml.transit.artifact.ArtifactNotFoundException;
-
-/**
- * Exception to indicate that a link could not be located.
- *
- * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
- * @version @PROJECT-VERSION@
- */
-public class LinkNotFoundException extends ArtifactNotFoundException
-{
- /**
- * Serial version identifier.
- */
- static final long serialVersionUID = 1L;
-
- //
------------------------------------------------------------------------
- // constructor
- //
------------------------------------------------------------------------
-
- /**
- * Construct a new <code>LinkNotFoundException</code> instance.
- *
- * @param message The detail message for this exception.
- * @param uri the link uri
- */
- public LinkNotFoundException( final String message, final URI uri )
- {
- super( message, uri );
- }
-}
-

Modified:
trunk/main/transit/core/src/main/dpml/transit/link/LinkURLConnection.java
===================================================================
---
trunk/main/transit/core/src/main/net/dpml/transit/link/LinkURLConnection.java
2007-01-10 20:29:19 UTC (rev 1810)
+++ trunk/main/transit/core/src/main/dpml/transit/link/LinkURLConnection.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -1,6 +1,5 @@
/*
- * Copyright 2005 Niclas Hedhman
- * Copyright 2005 Stephen J. McConnell.
+ * Copyright 2006-2007 Stephen J. McConnell.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,7 +16,7 @@
* limitations under the License.
*/

-package net.dpml.transit.link;
+package dpml.transit.link;

import java.io.IOException;
import java.io.InputStream;
@@ -33,7 +32,7 @@
import net.dpml.transit.Transit;
import net.dpml.transit.Artifact;
import net.dpml.transit.UnsupportedSchemeException;
-import net.dpml.util.MimeTypeHandler;
+import net.dpml.transit.LinkManager;

/**
* link: URL protocol connection processor.
@@ -42,8 +41,10 @@
*/
public class LinkURLConnection extends URLConnection
{
+ private static final String LINK_MIME_TYPE = "application/x-dpml-link";
+
private boolean m_connected;
- private URL m_targetURL;
+ private URL m_targetURL;

/**
* Creation of a new handler.
@@ -76,7 +77,7 @@
try
{
AccessController.doPrivileged(
- new PrivilegedExceptionAction()
+ new PrivilegedExceptionAction<Object>()
{
public Object run()
throws IOException
@@ -86,15 +87,7 @@
URI targetUri = manager.getTargetURI( linkUri );
if( targetUri != null )
{
- try
- {
- Artifact artifact = Artifact.createArtifact(
targetUri );
- m_targetURL = artifact.toURL();
- }
- catch( UnsupportedSchemeException use )
- {
- m_targetURL = new URL( targetUri.toASCIIString()
);
- }
+ m_targetURL = Artifact.toURL( targetUri );
}
else
{
@@ -159,9 +152,9 @@
*/
public String getContentType()
{
- return MimeTypeHandler.getMimeType( "link" );
+ return LINK_MIME_TYPE;
}
-
+
/**
* Return the content for this Link.
* @param classes a sequence of classes against which the
@@ -175,20 +168,13 @@
final LinkManager manager = Transit.getInstance().getLinkManager();

Object result = AccessController.doPrivileged(
- new PrivilegedAction()
+ new PrivilegedAction<Object>()
{
public Object run()
{
for( int i=0; i < classes.length; i++ )
{
Class c = classes[i];
- if( c.equals( Link.class ) )
- {
- String extUri = getURL().toString();
- URI uri = URI.create( extUri );
- Link link = new Link( uri, manager );
- return link;
- }
if( c.equals( URI.class ) )
{
String extUri = getURL().toString();
@@ -218,4 +204,23 @@
}
}
}
+
+ /**
+ * Return the link content by delegating to the underlying artifact.
+ * @return the artifact content
+ * @exception IOException if an IO error occurs
+ */
+ public Object getContent()
+ throws IOException
+ {
+ connect();
+ if( null != m_targetURL )
+ {
+ return m_targetURL.getContent();
+ }
+ else
+ {
+ return super.getContent();
+ }
+ }
}

Added: trunk/main/transit/core/src/main/dpml/transit/link/package-info.java
===================================================================
--- trunk/main/transit/core/src/main/net/dpml/transit/link/package-info.java
2007-01-10 20:29:19 UTC (rev 1810)
+++ trunk/main/transit/core/src/main/dpml/transit/link/package-info.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2007 Stephen J. McConnell.
+ *
+ * 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.
+ */
+
+/**
+ * Transit <tt>link</tt> protocol handler.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+package dpml.transit.link;

Deleted: trunk/main/transit/core/src/main/dpml/transit/link/package.html
===================================================================
--- trunk/main/transit/core/src/main/net/dpml/transit/link/package.html
2007-01-10 20:29:19 UTC (rev 1810)
+++ trunk/main/transit/core/src/main/dpml/transit/link/package.html
2007-02-08 23:42:59 UTC (rev 1833)
@@ -1,5 +0,0 @@
-
-<body>
-<p>Protocol handler for uris artifact links.</p>
-</body>
-

Copied: trunk/main/transit/core/src/main/dpml/transit/local (from rev 1810,
trunk/main/transit/core/src/main/net/dpml/transit/local)

Modified: trunk/main/transit/core/src/main/dpml/transit/local/Handler.java
===================================================================
--- trunk/main/transit/core/src/main/net/dpml/transit/local/Handler.java
2007-01-10 20:29:19 UTC (rev 1810)
+++ trunk/main/transit/core/src/main/dpml/transit/local/Handler.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -1,5 +1,5 @@
/*
- * Copyright 2005 Stephen McConnell
+ * Copyright 2005-2007 Stephen McConnell
* 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
@@ -15,10 +15,11 @@
* limitations under the License.
*/

-package net.dpml.transit.local;
+package dpml.transit.local;

+import dpml.transit.TransitContext;
+
import java.io.IOException;
-
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
@@ -53,6 +54,7 @@
protected URLConnection openConnection( final URL url )
throws IOException
{
- return new LocalURLConnection( url );
+ TransitContext context = TransitContext.getInstance();
+ return new LocalURLConnection( url, context );
}
}

Modified:
trunk/main/transit/core/src/main/dpml/transit/local/LocalURLConnection.java
===================================================================
---
trunk/main/transit/core/src/main/net/dpml/transit/local/LocalURLConnection.java
2007-01-10 20:29:19 UTC (rev 1810)
+++
trunk/main/transit/core/src/main/dpml/transit/local/LocalURLConnection.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -1,5 +1,5 @@
/*
- * Copyright 2005 Stephen J. McConnell.
+ * Copyright 2005-2007 Stephen J. McConnell.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,8 +16,10 @@
* limitations under the License.
*/

-package net.dpml.transit.local;
+package dpml.transit.local;

+import dpml.transit.TransitContext;
+
import java.io.IOException;
import java.io.InputStream;
import java.io.FileInputStream;
@@ -34,6 +36,8 @@

import net.dpml.transit.Transit;
import net.dpml.transit.Artifact;
+import net.dpml.transit.ArtifactException;
+import net.dpml.transit.ContentHandler;

/**
* The local URL protocol connection implementation.
@@ -42,6 +46,11 @@
*/
public class LocalURLConnection extends URLConnection
{
+ /**
+ * Transit context.
+ */
+ private final TransitContext m_context;
+
private boolean m_connected;

private File m_target;
@@ -51,11 +60,12 @@
* @param url the url to establish a connection with
* @exception NullPointerException if the url argument is null
*/
- LocalURLConnection( URL url )
+ LocalURLConnection( URL url, TransitContext context )
throws NullPointerException
{
super( url );

+ m_context = context;
m_connected = false;
}

@@ -78,7 +88,7 @@
try
{
AccessController.doPrivileged(
- new PrivilegedExceptionAction()
+ new PrivilegedExceptionAction<Object>()
{
public Object run()
throws IOException
@@ -91,7 +101,7 @@
String artifactName = artifact.getName();
String typeSpec = artifact.getType();
String versionSpec = artifact.getVersion();
- File prefs = Transit.DPML_PREFS;
+ File prefs = Transit.PREFS;
File group = new File( prefs, groupSpec );
File type = new File( group, typeSpec + "s" );
if( null == versionSpec )
@@ -182,7 +192,7 @@
{
connect();
Object result = AccessController.doPrivileged(
- new PrivilegedAction()
+ new PrivilegedAction<Object>()
{
public Object run()
{
@@ -207,9 +217,29 @@
{
if( null != m_target )
{
- URI uri = m_target.toURI();
- URL url = uri.toURL();
- return url.getContent( classes );
+ String spec = url.toExternalForm();
+ try
+ {
+ Artifact artifact = Artifact.createArtifact( spec );
+ String type = artifact.getType();
+ ContentHandler handler = m_context.getContentHandler(
type );
+ if( null != handler )
+ {
+ URLConnection connection =
m_target.toURI().toURL().openConnection();
+ return handler.getContent( connection, classes );
+ }
+ else
+ {
+ URLConnection connection =
m_target.toURI().toURL().openConnection();
+ return connection.getContent( classes );
+ }
+ }
+ catch( Exception e )
+ {
+ final String error =
+ "Internal error in local url connection handler.";
+ throw new ArtifactException( error, e );
+ }
}
else
{
@@ -217,4 +247,45 @@
}
}
}
+
+ /**
+ * Return the link content by delegating to the underlying artifact.
+ * @return the artifact content
+ * @exception IOException if an IO error occurs
+ */
+ public Object getContent()
+ throws IOException
+ {
+ connect();
+ if( null != m_target )
+ {
+ String spec = url.toExternalForm();
+ try
+ {
+ Artifact artifact = Artifact.createArtifact( spec );
+ String type = artifact.getType();
+ ContentHandler handler = m_context.getContentHandler( type );
+ if( null != handler )
+ {
+ URLConnection connection =
m_target.toURI().toURL().openConnection();
+ return handler.getContent( connection );
+ }
+ else
+ {
+ URLConnection connection =
m_target.toURI().toURL().openConnection();
+ return connection.getContent();
+ }
+ }
+ catch( Exception e )
+ {
+ final String error =
+ "Internal error in local url connection handler.";
+ throw new ArtifactException( error, e );
+ }
+ }
+ else
+ {
+ return super.getContent();
+ }
+ }
}

Added: trunk/main/transit/core/src/main/dpml/transit/local/package-info.java
===================================================================
--- trunk/main/transit/core/src/main/net/dpml/transit/local/package-info.java
2007-01-10 20:29:19 UTC (rev 1810)
+++ trunk/main/transit/core/src/main/dpml/transit/local/package-info.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2007 Stephen J. McConnell.
+ *
+ * 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.
+ */
+
+/**
+ * Transit <tt>local</tt> protocol handler.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+package dpml.transit.local;

Deleted: trunk/main/transit/core/src/main/dpml/transit/local/package.html
===================================================================
--- trunk/main/transit/core/src/main/net/dpml/transit/local/package.html
2007-01-10 20:29:19 UTC (rev 1810)
+++ trunk/main/transit/core/src/main/dpml/transit/local/package.html
2007-02-08 23:42:59 UTC (rev 1833)
@@ -1,12 +0,0 @@
-
-<body>
-<p>
-Local preference resource protocol handler.
-The local package holds a protocol handler that resolves uri references to
content
-under the ${dpml.prefs} directory. A uri such as
"local:template:magic/standard" is
-equivalent to the following file path:
${dpml.prefs}/magic/templates/standard.template.
-The handler's primary function is to allow references to ${dpml.prefs)
content without
-the prerequisite of symbolic substitution by a controlling application.
-</p>.
-</body>
-

Added: trunk/main/transit/core/src/main/dpml/transit/package-info.java
===================================================================
--- trunk/main/transit/core/src/main/dpml/transit/package-info.java
2007-02-08 23:39:34 UTC (rev 1832)
+++ trunk/main/transit/core/src/main/dpml/transit/package-info.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2004-2007 Stephen J. McConnell.
+ *
+ * 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.
+ */
+
+/**
+ * Internal implementation of the Transit system cache, host controllers,
+ * monitors, and content handling machinery.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+package dpml.transit;

Added: trunk/main/transit/core/src/main/dpml/util/CLIHelper.java
===================================================================
--- trunk/main/transit/core/src/main/dpml/util/CLIHelper.java 2007-02-08
23:39:34 UTC (rev 1832)
+++ trunk/main/transit/core/src/main/dpml/util/CLIHelper.java 2007-02-08
23:42:59 UTC (rev 1833)
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2005-2007 Stephen J. McConnell.
+ *
+ * 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 dpml.util;
+
+import java.util.ArrayList;
+
+/**
+ * CLI hander for the depot package.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public final class CLIHelper
+{
+ private CLIHelper()
+ {
+ // static utility
+ }
+
+ /**
+ * Utility operation to consolidate a supplied array of command line
arguments
+ * by removal of the supplied argument.
+ *
+ * @param args the command line arguments to consolidate
+ * @param argument the argument to remove
+ * @return the consolidated argument array
+ */
+ public static String[] consolidate( String [] args, String argument )
+ {
+ return consolidate( args, argument, 0 );
+ }
+
+ /**
+ * Utility operation to consolidate a supplied array of command line
arguments
+ * by removal of the supplied argument and the subsequent parameter
values.
+ *
+ * @param args the command line arguments to consolidate
+ * @param argument the argument to remove
+ * @param n the number of parameters to consolidate
+ * @return the consolidated argument array
+ */
+ public static String[] consolidate( String [] args, String argument, int
n )
+ {
+ boolean flag = false;
+ ArrayList<String> list = new ArrayList<String>();
+ for( int i=0; i < args.length; i++ )
+ {
+ String arg = args[i];
+ if( flag )
+ {
+ list.add( arg );
+ }
+ else
+ {
+ if( arg.equals( argument ) )
+ {
+ flag = true;
+ i = i+n;
+ }
+ else
+ {
+ list.add( arg );
+ }
+ }
+ }
+ return list.toArray( new String[0] );
+ }
+
+ /**
+ * Test is the supplied option is present in the set of supplied command
line
+ * arguments.
+ *
+ * @param args the set of command line arguments to test against
+ * @param flag the command line option to test for
+ * @return TRUE if one of the command line options matching the supplied
falg argument
+ */
+ public static boolean isOptionPresent( String[] args, String flag )
+ {
+ for( int i=0; i < args.length; i++ )
+ {
+ String arg = args[i];
+ if( arg.equals( flag ) )
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Return a command line argument immediately following an option.
+ * @param args an array of command line arguments
+ * @param option the command line option used as the key to locate the
option value
+ * @return the option argument value
+ */
+ public static String getOption( String[] args, String option )
+ {
+ for( int i=0; i < args.length; i++ )
+ {
+ String arg = args[i];
+ if( arg.equals( option ) )
+ {
+ try
+ {
+ return args[i+1];
+ }
+ catch( IndexOutOfBoundsException e )
+ {
+ final String error =
+ "Requestion option ["
+ + option
+ + "] is not followed by an argument value.";
+ throw new IllegalArgumentException( error );
+ }
+ }
+ }
+ final String error =
+ "Option does not exist within the supplied commandline.";
+ throw new IllegalArgumentException( error );
+ }
+}
+

Added: trunk/main/transit/core/src/main/dpml/util/Category.java
===================================================================
--- trunk/main/transit/core/src/main/dpml/util/Category.java 2007-02-08
23:39:34 UTC (rev 1832)
+++ trunk/main/transit/core/src/main/dpml/util/Category.java 2007-02-08
23:42:59 UTC (rev 1833)
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2006 Stephen J. McConnell.
+ *
+ * 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 dpml.util;
+
+/**
+ * Classoader category enumeration.
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public enum Category
+{
+ /**
+ * System category.
+ */
+ SYSTEM,
+
+ /**
+ * API category.
+ */
+ PUBLIC,
+
+ /**
+ * SPI category.
+ */
+ PROTECTED,
+
+ /**
+ * Implementation category.
+ */
+ PRIVATE;
+
+ /**
+ * Return a category given a supplied ordinal value.
+ * @param index the ordinal value
+ * @return the category
+ */
+ public static Category valueOf( final int index )
+ {
+ if( index == SYSTEM.ordinal() )
+ {
+ return SYSTEM;
+ }
+ else if( index == PUBLIC.ordinal() )
+ {
+ return PUBLIC;
+ }
+ else if( index == PROTECTED.ordinal() )
+ {
+ return PROTECTED;
+ }
+ else if( index == PRIVATE.ordinal() )
+ {
+ return PRIVATE;
+ }
+ else
+ {
+ final String error =
+ "Category ordinal [" + index + "] is not a valid value.";
+ throw new IllegalArgumentException( error );
+ }
+ }
+}

Copied: trunk/main/transit/core/src/main/dpml/util/ConfigurationHandler.java
(from rev 1789,
trunk/main/transit/core/src/main/net/dpml/util/ConfigurationHandler.java)
===================================================================
--- trunk/main/transit/core/src/main/net/dpml/util/ConfigurationHandler.java
2006-11-30 21:08:46 UTC (rev 1789)
+++ trunk/main/transit/core/src/main/dpml/util/ConfigurationHandler.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2005-2007 Stephen McConnell.
+ *
+ * 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 dpml.util;
+
+import java.net.URL;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.util.Properties;
+import java.util.logging.LogManager;
+
+import net.dpml.transit.Transit;
+
+import static net.dpml.transit.Transit.DATA;
+
+/**
+ * Utility class used to establish the logging configuration.
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class ConfigurationHandler
+{
+ /**
+ * Creation of the logging controller.
+ */
+ public ConfigurationHandler()
+ {
+
+ //
+ // customize the configuration based on a properties file declared
under
+ // the 'dpml.logging.config' property
+ //
+
+ Properties properties = new Properties();
+ String config = System.getProperty( "dpml.logging.config" );
+ if( null != config )
+ {
+ Properties sys = System.getProperties();
+ String spec = PropertyResolver.resolve( sys, config );
+ try
+ {
+ URL url = new URL( spec );
+ InputStream stream = url.openStream();
+ properties.load( stream );
+ properties = PropertyResolver.resolve( sys, properties );
+ }
+ catch( FileNotFoundException e )
+ {
+ final String error =
+ "Logging configuration does not exist."
+ + "\nURI: " + spec;
+ System.err.println( error );
+ }
+ catch( Exception e )
+ {
+ System.out.println( "Error loading user properties: " +
config );
+ e.printStackTrace();
+ }
+ }
+
+ //
+ // ensure that sensible defaults exist
+ //
+
+ if( null == properties.getProperty( ".level" ) )
+ {
+ String level = getDefaultLevel();
+ properties.setProperty( ".level", level );
+ }
+
+ if( null == properties.getProperty( "handlers" ) )
+ {
+ setProperty( properties,
+ "handlers",
+ "java.util.logging.ConsoleHandler" );
+ setProperty( properties,
+ "java.util.logging.ConsoleHandler.formatter",
+ "dpml.util.StandardFormatter" );
+ setProperty( properties,
"java.util.logging.ConsoleHandler.level", "ALL" );
+ }
+
+ File base = new File( System.getProperty( "user.dir" ) );
+ File file = new File( base, "logging.properties" );
+ if( file.exists() )
+ {
+ try
+ {
+ InputStream input = new FileInputStream( file );
+ properties.load( input );
+ }
+ catch( Throwable e )
+ {
+ e.printStackTrace();
+ }
+ }
+
+ //
+ // convert the resolved properties instance to an input stream
+ // and supply this to the log manager
+ //
+
+ try
+ {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ properties.store( out, "DPML Logging Properties" );
+ byte[] bytes = out.toByteArray();
+ ByteArrayInputStream input = new ByteArrayInputStream( bytes );
+ LogManager manager = LogManager.getLogManager();
+ manager.readConfiguration( input );
+ }
+ catch( Throwable e )
+ {
+ e.printStackTrace();
+ }
+ }
+
+ private void setProperty( Properties properties, String key, String
value )
+ {
+ properties.setProperty( key, System.getProperty( key, value ) );
+ }
+
+ private String getDefaultLevel()
+ {
+ //if( "true".equals( System.getProperty( "dpml.debug" ) ) )
+ //{
+ // return "FINE";
+ //}
+ //else
+ //{
+ return System.getProperty( "dpml.logging.level", "INFO"
).toUpperCase();
+ //}
+ }
+}

Copied: trunk/main/transit/core/src/main/dpml/util/DefaultLogger.java (from
rev 1789, trunk/main/transit/core/src/main/net/dpml/util/DefaultLogger.java)
===================================================================
--- trunk/main/transit/core/src/main/net/dpml/util/DefaultLogger.java
2006-11-30 21:08:46 UTC (rev 1789)
+++ trunk/main/transit/core/src/main/dpml/util/DefaultLogger.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,268 @@
+/*
+ * Copyright 2006-2007 Stephen J. McConnell.
+ *
+ * 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 dpml.util;
+
+import java.util.logging.Logger;
+import java.util.logging.Level;
+
+/**
+ * Generic logging channel.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public final class DefaultLogger implements net.dpml.util.Logger
+{
+ //
------------------------------------------------------------------------
+ // static
+ //
------------------------------------------------------------------------
+
+ private static final PID ID = new PID();
+
+ private static String clean( String category )
+ {
+ if( null == category )
+ {
+ return "";
+ }
+ String result = category.replace( '/', '.' );
+ if( result.startsWith( "." ) )
+ {
+ return clean( result.substring( 1 ) );
+ }
+ else if( result.endsWith( "." ) )
+ {
+ return clean( result.substring( 0, result.length() -1 ) );
+ }
+ else
+ {
+ return result;
+ }
+ }
+
+ //
------------------------------------------------------------------------
+ // state
+ //
------------------------------------------------------------------------
+
+ private Logger m_logger;
+
+ //
------------------------------------------------------------------------
+ // constructor
+ //
------------------------------------------------------------------------
+
+ /**
+ * Creation of a new console adapter that is used to redirect transit
events
+ * the system output stream.
+ */
+ public DefaultLogger()
+ {
+ this( "" );
+ }
+
+ /**
+ * Creation of a new console adapter that is used to redirect transit
events
+ * the system output stream.
+ * @param category the logging channel category name
+ */
+ public DefaultLogger( String category )
+ {
+ this( Logger.getLogger( clean( category ) ) );
+ }
+
+ /**
+ * Creation of a new console adapter that is used to redirect transit
events
+ * the system output stream.
+ * @param logger the assigned logging channel
+ */
+ public DefaultLogger( Logger logger )
+ {
+ m_logger = logger;
+ }
+
+ //
------------------------------------------------------------------------
+ // Logger
+ //
------------------------------------------------------------------------
+
+ /**
+ * Return TRUE is trace level logging is enabled.
+ * @return the enabled state of trace logging
+ */
+ public boolean isTraceEnabled()
+ {
+ return m_logger.isLoggable( Level.FINER );
+ }
+
+ /**
+ * Return TRUE is debug level logging is enabled.
+ * @return the enabled state of debug logging
+ */
+ public boolean isDebugEnabled()
+ {
+ return m_logger.isLoggable( Level.FINE );
+ }
+
+ /**
+ * Return TRUE is info level logging is enabled.
+ * @return the enabled state of info logging
+ */
+ public boolean isInfoEnabled()
+ {
+ return m_logger.isLoggable( Level.INFO );
+ }
+
+ /**
+ * Return TRUE is error level logging is enabled.
+ * @return the enabled state of error logging
+ */
+ public boolean isWarnEnabled()
+ {
+ return m_logger.isLoggable( Level.WARNING );
+ }
+
+ /**
+ * Return TRUE is error level logging is enabled.
+ * @return the enabled state of error logging
+ */
+ public boolean isErrorEnabled()
+ {
+ return m_logger.isLoggable( Level.SEVERE );
+ }
+
+ /**
+ * Log a debug message is trace mode is enabled.
+ * @param message the message to log
+ */
+ public void trace( String message )
+ {
+ if( isTraceEnabled() )
+ {
+ m_logger.finer( message );
+ }
+ }
+
+ /**
+ * Log a debug message is debug mode is enabled.
+ * @param message the message to log
+ */
+ public void debug( String message )
+ {
+ if( isDebugEnabled() )
+ {
+ m_logger.fine( message );
+ }
+ }
+
+ /**
+ * Log a info level message.
+ * @param message the message to log
+ */
+ public void info( String message )
+ {
+ if( isInfoEnabled() )
+ {
+ m_logger.info( message );
+ }
+ }
+
+ /**
+ * Record a warning message.
+ * @param message the warning message to record
+ */
+ public void warn( String message )
+ {
+ if( isWarnEnabled() )
+ {
+ m_logger.warning( message );
+ }
+ }
+
+ /**
+ * Record a warning message.
+ * @param message the warning message to record
+ * @param cause the causal exception
+ */
+ public void warn( String message, Throwable cause )
+ {
+ if( isWarnEnabled() )
+ {
+ m_logger.log( Level.WARNING, message, cause );
+ }
+ }
+
+ /**
+ * Log a error message.
+ * @param message the message to log
+ */
+ public void error( String message )
+ {
+ if( isErrorEnabled() )
+ {
+ m_logger.log( Level.SEVERE, message );
+ }
+ }
+
+ /**
+ * Log a error message.
+ * @param message the message to log
+ * @param e the causal exception
+ */
+ public void error( String message, Throwable e )
+ {
+ if( isErrorEnabled() )
+ {
+ m_logger.log( Level.SEVERE, message, e );
+ }
+ }
+
+ /**
+ * Return a child logger.
+ * @param category the sub-category name.
+ * @return the child logging channel
+ */
+ public net.dpml.util.Logger getChildLogger( String category )
+ {
+ if( ( null == category ) || "".equals( category ) )
+ {
+ return this;
+ }
+ else
+ {
+ String name = m_logger.getName();
+ String path = trim( name + "." + category );
+ return new DefaultLogger( Logger.getLogger( path ) );
+ }
+ }
+
+ private String trim( String path )
+ {
+ if( path.startsWith( "." ) )
+ {
+ return trim( path.substring( 1 ) );
+ }
+ else if( ".".equals( path ) )
+ {
+ return "";
+ }
+ else
+ {
+ return path;
+ }
+ }
+}
+

Added: trunk/main/transit/core/src/main/dpml/util/DepotHandler.java
===================================================================
--- trunk/main/transit/core/src/main/dpml/util/DepotHandler.java
2007-02-08 23:39:34 UTC (rev 1832)
+++ trunk/main/transit/core/src/main/dpml/util/DepotHandler.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2005-2006 Stephen McConnell.
+ *
+ * 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 dpml.util;
+
+import java.io.OutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.BufferedOutputStream;
+import java.net.Socket;
+import java.net.SocketException;
+import java.util.logging.Handler;
+import java.util.logging.LogRecord;
+
+/**
+ * Logging message handler that redirects log messages from a subprocess to
+ * a remote logging system.
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class DepotHandler extends Handler
+{
+ private static final PID ID = new PID();
+
+ private final Socket m_socket;
+ private final OutputStream m_output;
+ private final ObjectOutputStream m_stream;
+
+ /**
+ * Creation of a new handler instance.
+ * @exception Exception if an error occurs
+ */
+ public DepotHandler() throws Exception
+ {
+ this( "localhost", 2020 );
+ }
+
+ /**
+ * Creation of a new handler instance.
+ * @param host the log server host
+ * @param port the port
+ * @exception IOException if an IO error occurs
+ */
+ public DepotHandler( String host, int port ) throws IOException
+ {
+ m_socket = new Socket( host, port );
+ m_output = m_socket.getOutputStream();
+ m_stream = new ObjectOutputStream( new BufferedOutputStream(
m_output ) );
+ }
+
+ /**
+ * Flush the handler.
+ */
+ public void flush()
+ {
+ }
+
+ /**
+ * Close the log record handler.
+ */
+ public void close()
+ {
+ try
+ {
+ m_output.close();
+ }
+ catch( Exception e )
+ {
+ e.printStackTrace();
+ }
+ try
+ {
+ m_socket.close();
+ }
+ catch( Exception e )
+ {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Publish a log record. The implementation packages the supplied log
+ * record under a LogStatement, binding the record with the associated
process
+ * identifier. The statement is subsequently writen to a socket
established
+ * within the instance constructor.
+ *
+ * @param record the log record to publish
+ */
+ public void publish( LogRecord record )
+ {
+ synchronized( m_socket )
+ {
+ if( m_socket.isClosed() )
+ {
+ return;
+ }
+
+ try
+ {
+ LogStatement statement = new LogStatement( ID, record );
+ m_stream.writeObject( statement );
+ m_stream.flush();
+ }
+ catch( SocketException e )
+ {
+ e.printStackTrace();
+ }
+ catch( Exception e )
+ {
+ e.printStackTrace();
+ }
+ }
+ }
+}
+

Added:
trunk/main/transit/core/src/main/dpml/util/DepotLoggingConfiguration.java
===================================================================
--- trunk/main/transit/core/src/main/dpml/util/DepotLoggingConfiguration.java
2007-02-08 23:39:34 UTC (rev 1832)
+++ trunk/main/transit/core/src/main/dpml/util/DepotLoggingConfiguration.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2005 Stephen McConnell.
+ *
+ * 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 dpml.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.Properties;
+import java.util.logging.LogManager;
+
+/**
+ * Utility class used to establish the logging configuration for managed
subprocesses.
+ * The handler redirects logging records to a remote LoggingService via RMI
that
+ * aggregates logging messages from multiple JVM within a local domain.
This
+ * configuration handler is declared as the default logging configuration
for
+ * suprocesses launched by the DPML Station.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class DepotLoggingConfiguration
+{
+ /**
+ * Creation of the logging controller.
+ */
+ public DepotLoggingConfiguration()
+ {
+ String group = System.getProperty( "dpml.system.group", "root" );
+ String level = getDefaultLevel();
+
+ Properties properties = new Properties();
+
+ properties.setProperty(
+ "handlers",
+ System.getProperty(
+ "handlers",
+ DepotHandler.class.getName() ) );
+
+ //
+ // set the default level by setting the root logger level
+ //
+
+ properties.setProperty( ".level", level );
+
+ try
+ {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ properties.store( out, "DPML Logging properties" );
+ byte[] bytes = out.toByteArray();
+ ByteArrayInputStream input = new ByteArrayInputStream( bytes );
+ LogManager manager = LogManager.getLogManager();
+ manager.readConfiguration( input );
+ }
+ catch( Throwable e )
+ {
+ e.printStackTrace();
+ }
+ }
+
+ private String getDefaultLevel()
+ {
+ if( "true".equals( System.getProperty( "dpml.debug" ) ) )
+ {
+ return "FINE";
+ }
+ else
+ {
+ return System.getProperty( "dpml.logging.level", "INFO"
).toUpperCase();
+ }
+ }
+}
+

Copied: trunk/main/transit/core/src/main/dpml/util/ElementHelper.java (from
rev 1789, trunk/main/transit/core/src/main/net/dpml/util/ElementHelper.java)
===================================================================
--- trunk/main/transit/core/src/main/net/dpml/util/ElementHelper.java
2006-11-30 21:08:46 UTC (rev 1789)
+++ trunk/main/transit/core/src/main/dpml/util/ElementHelper.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,395 @@
+/*
+ * Copyright 2004-2007 Stephen McConnell
+ *
+ * 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 dpml.util;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.Properties;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import net.dpml.util.Resolver;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * Utility class supporting the translation of DOM content into local child,
children,
+ * attribute and value values.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public final class ElementHelper
+{
+ private static final Resolver SIMPLE_RESOLVER = new SimpleResolver();
+
+ private ElementHelper()
+ {
+ // utility class
+ }
+
+ /**
+ * Return the root element of the supplied file.
+ * @param definition the file to load
+ * @return the root element
+ * @exception Exception if the error occurs during root element
establishment
+ */
+ public static Element getRootElement( final File definition )
+ throws Exception
+ {
+ if( !definition.exists() )
+ {
+ throw new FileNotFoundException( definition.toString() );
+ }
+
+ if( !definition.isFile() )
+ {
+ final String error =
+ "Source is not a file: " + definition;
+ throw new IllegalArgumentException( error );
+ }
+
+ final DocumentBuilderFactory factory =
+ DocumentBuilderFactory.newInstance();
+ factory.setValidating( false );
+ factory.setNamespaceAware( false );
+ final Document document =
+ factory.newDocumentBuilder().parse( definition );
+ return document.getDocumentElement();
+ }
+
+ /**
+ * Return the root element of the supplied input stream.
+ * @param input the input stream containing a XML definition
+ * @return the root element
+ * @exception Exception if an error occurs
+ */
+ public static Element getRootElement( final InputStream input )
+ throws Exception
+ {
+ if( null == input )
+ {
+ throw new NullPointerException( "input" );
+ }
+ final DocumentBuilderFactory factory =
+ DocumentBuilderFactory.newInstance();
+ factory.setValidating( false );
+ factory.setNamespaceAware( false );
+ factory.setExpandEntityReferences( false );
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ return getRootElement( builder, input );
+ }
+
+ /**
+ * Return the root element of the supplied input stream.
+ * @param builder the document builder
+ * @param input the input stream containing a XML definition
+ * @return the root element
+ * @exception Exception if an error occurs
+ */
+ public static Element getRootElement( final DocumentBuilder builder,
final InputStream input )
+ throws Exception
+ {
+ if( null == input )
+ {
+ throw new NullPointerException( "input" );
+ }
+ if( null == builder )
+ {
+ throw new NullPointerException( "builder" );
+ }
+ final Document document = builder.parse( input );
+ return document.getDocumentElement();
+ }
+
+ /**
+ * Return a named child relative to a supplied element.
+ * @param root the parent DOM element
+ * @param name the name of a child element
+ * @return the child element of null if the child does not exist
+ */
+ public static Element getChild( final Element root, final String name )
+ {
+ if( null == root )
+ {
+ return null;
+ }
+ Element[] children = getChildren( root );
+ for( int i=0; i<children.length; i++ )
+ {
+ Element child = children[i];
+ //if( name.equals( child.getTagName() ) )
+ if( name.equals( child.getLocalName() ) )
+ {
+ return child;
+ }
+ else if( name.equals( child.getTagName() ) )
+ {
+ return child;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return all children matching the supplied element name.
+ * @param root the parent DOM element
+ * @param name the name against which child element will be matched
+ * @return the array of child elements with a matching name
+ */
+ public static Element[] getChildren( final Element root, final String
name )
+ {
+ if( null == root )
+ {
+ return new Element[0];
+ }
+ Element[] children = getChildren( root );
+ final ArrayList<Element> result = new ArrayList<Element>();
+ for( int i=0; i<children.length; i++ )
+ {
+ final Element child = children[i];
+ if( name.equals( child.getLocalName() ) )
+ {
+ result.add( child );
+ }
+ else if( name.equals( child.getTagName() ) )
+ {
+ result.add( child );
+ }
+ }
+ return (Element[]) result.toArray( new Element[0] );
+ }
+
+ /**
+ * Return all children of the supplied parent.
+ * @param root the parent DOM element
+ * @return the array of all children
+ */
+ public static Element[] getChildren( final Element root )
+ {
+ if( null == root )
+ {
+ return new Element[0];
+ }
+ final NodeList list = root.getChildNodes();
+ final int n = list.getLength();
+ if( n < 1 )
+ {
+ return new Element[0];
+ }
+ final ArrayList<Element> result = new ArrayList<Element>();
+ for( int i=0; i < n; i++ )
+ {
+ final Node item = list.item( i );
+ if( item instanceof Element )
+ {
+ result.add( (Element) item );
+ }
+ }
+ return (Element[]) result.toArray( new Element[0] );
+ }
+
+ /**
+ * Return the value of an element.
+ * @param node the DOM node
+ * @return the node value
+ */
+ public static String getValue( final Element node )
+ {
+ return getValue( node, null );
+ }
+
+ /**
+ * Return the value of an element.
+ * @param node the DOM node
+ * @param resolver a symbolic property name resolver
+ * @return the node value
+ */
+ public static String getValue( final Element node, Resolver resolver )
+ {
+ if( null == node )
+ {
+ return null;
+ }
+ String value;
+ if( node.getChildNodes().getLength() > 0 )
+ {
+ value = node.getFirstChild().getNodeValue();
+ }
+ else
+ {
+ value = node.getNodeValue();
+ }
+ return normalize( resolver, value );
+ }
+
+ /**
+ * Return the value of an element attribute.
+ * @param node the DOM node
+ * @param key the attribute key
+ * @return the attribute value or null if the attribute is undefined
+ */
+ public static String getAttribute( final Element node, final String key )
+ {
+ return getAttribute( node, key, null );
+ }
+
+ /**
+ * Return the value of an element attribute.
+ * @param node the DOM node
+ * @param key the attribute key
+ * @param def the default value if the attribute is undefined
+ * @return the attribute value or the default value if undefined
+ */
+ public static String getAttribute( final Element node, final String key,
final String def )
+ {
+ return getAttribute( node, key, def, null );
+ }
+
+ /**
+ * Return the value of an element attribute.
+ * @param node the DOM node
+ * @param key the attribute key
+ * @param def the default value if the attribute is undefined
+ * @param resolver a symbolic property name resolver
+ * @return the attribute value or the default value if undefined
+ */
+ public static String getAttribute(
+ final Element node, final String key, final String def, Resolver
resolver )
+ {
+ if( null == node )
+ {
+ return def;
+ }
+ if( !node.hasAttribute( key ) )
+ {
+ return def;
+ }
+ String v = node.getAttribute( key );
+ return normalize( resolver, v );
+ }
+
+ /**
+ * Return the value of an element attribute as a boolean
+ * @param node the DOM node
+ * @param key the attribute key
+ * @return the attribute value as a boolean or false if undefined
+ */
+ public static boolean getBooleanAttribute( final Element node, final
String key )
+ {
+ return getBooleanAttribute( node, key, false );
+ }
+
+ /**
+ * Return the value of an element attribute as a boolean.
+ * @param node the DOM node
+ * @param key the attribute key
+ * @param def the default value if the attribute is undefined
+ * @return the attribute value or the default value if undefined
+ */
+ public static boolean getBooleanAttribute( final Element node, final
String key, final boolean def )
+ {
+ return getBooleanAttribute( node, key, def, null );
+ }
+
+ /**
+ * Return the value of an element attribute as a boolean.
+ * @param node the DOM node
+ * @param key the attribute key
+ * @param def the default value if the attribute is undefined
+ * @param resolver a symbolic property name resolver
+ * @return the attribute value or the default value if undefined
+ */
+ public static boolean getBooleanAttribute(
+ final Element node, final String key, final boolean def, Resolver
resolver )
+ {
+ if( null == node )
+ {
+ return def;
+ }
+
+ if( !node.hasAttribute( key ) )
+ {
+ return def;
+ }
+
+ String value = node.getAttribute( key );
+ value = normalize( resolver, value );
+ if( value.equals( "" ) )
+ {
+ return def;
+ }
+ if( value.equalsIgnoreCase( "true" ) )
+ {
+ return true;
+ }
+ if( value.equalsIgnoreCase( "false" ) )
+ {
+ return false;
+ }
+ final String error =
+ "Boolean argument [" + value + "] not recognized.";
+ throw new IllegalArgumentException( error );
+ }
+
+ /**
+ * Parse the value for any property tokens relative to system properties.
+ * @param value the value to parse
+ * @return the normalized string
+ */
+ //static String normalize( String value )
+ //{
+ // return SIMPLE_RESOLVER.resolve( value );
+ //}
+
+ /**
+ * Parse the value for any property tokens relative to system properties.
+ * @param value the value to parse
+ * @return the normalized string
+ */
+ static String normalize( Resolver resolver, String value )
+ {
+ if( null != resolver )
+ {
+ return resolver.resolve( value );
+ }
+ else
+ {
+ return value;
+ }
+ }
+
+ /**
+ * Parse the value for any property tokens relative to the supplied
properties.
+ * @param value the value to parse
+ * @param props the reference properties
+ * @return the normalized string
+ */
+ //static String normalize( String value, Properties props )
+ //{
+ // return PropertyResolver.resolve( props, value );
+ //}
+}

Copied: trunk/main/transit/core/src/main/dpml/util/ExceptionHelper.java (from
rev 1789, trunk/main/transit/core/src/main/net/dpml/util/ExceptionHelper.java)
===================================================================
--- trunk/main/transit/core/src/main/net/dpml/util/ExceptionHelper.java
2006-11-30 21:08:46 UTC (rev 1789)
+++ trunk/main/transit/core/src/main/dpml/util/ExceptionHelper.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,365 @@
+/*
+ * Copyright 2004-2007 Stephen J. McConnell.
+ *
+ * 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 dpml.util;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.Method;
+import java.util.StringTokenizer;
+
+/**
+ * General utilities supporting the packaging of exception messages.
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public final class ExceptionHelper
+{
+ //
------------------------------------------------------------------------
+ // static
+ //
------------------------------------------------------------------------
+
+ /**
+ * Returns the exception and causal exceptions as a formatted string.
+ * @param e the exception
+ * @return String the formatting string
+ */
+ public static String packException( final Throwable e )
+ {
+ return packException( null, e );
+ }
+
+ /**
+ * Returns the exception and causal exceptions as a formatted string.
+ * @param e the exception
+ * @param stack TRUE to generate a stack trace
+ * @return String the formatting string
+ */
+ public static String packException( final Throwable e, boolean stack )
+ {
+ return packException( null, e, stack );
+ }
+
+
+ /**
+ * Returns the exception and causal exceptions as a formatted string.
+ * @param message the header message
+ * @param e the exception
+ * @return String the formatting string
+ */
+ public static String packException( final String message, final
Throwable e )
+ {
+ return packException( message, e, false );
+ }
+
+ /**
+ * Returns the exception and causal exceptions as a formatted string.
+ * @param message the header message
+ * @param e the exception
+ * @param stack TRUE to generate a stack trace
+ * @return String the formatting string
+ */
+ public static String packException(
+ final String message, final Throwable e, boolean stack )
+ {
+ StringBuffer buffer = new StringBuffer();
+ packException( buffer, 0, message, e, stack );
+ buffer.append( getLine( END ) );
+ return buffer.toString();
+ }
+
+
+ /**
+ * Returns the exception and causal exceptions as a formatted string.
+ * @param message the header message
+ * @param e the exceptions
+ * @param stack TRUE to generate a stack trace
+ * @return String the formatting string
+ */
+ public static String packException(
+ final String message, final Throwable[] e, boolean stack )
+ {
+ final String lead = COMPOSITE + "(" + e.length + " entries) ";
+ StringBuffer buffer = new StringBuffer( getLine( lead ) );
+ if( null != message )
+ {
+ buffer.append( message );
+ buffer.append( "\n" );
+ }
+ for( int i=0; i < e.length; i++ )
+ {
+ packException( buffer, i + 1, null, e[i], stack );
+ }
+ buffer.append( getLine( END ) );
+ return buffer.toString();
+ }
+
+ //
------------------------------------------------------------------------
+ // static implementation
+ //
------------------------------------------------------------------------
+
+ /**
+ * Line separator character.
+ */
+ private static final String LINE_SEPARATOR =
+ System.getProperty( "line.separator" );
+
+ /**
+ * Header token.
+ */
+ private static final String HEADER = "----";
+
+ /**
+ * Exception token.
+ */
+ private static final String EXCEPTION = HEADER + " exception report ";
+
+ /**
+ * Composite token.
+ */
+ private static final String COMPOSITE = HEADER + " composite report ";
+
+ /**
+ * Runtime token.
+ */
+ private static final String RUNTIME = HEADER + " runtime exception
report ";
+
+ /**
+ * Error token.
+ */
+ private static final String ERROR = HEADER + " error report ";
+
+ /**
+ * Cause token.
+ */
+ private static final String CAUSE = HEADER + " cause ";
+
+ /**
+ * Trace token.
+ */
+ private static final String TRACE = HEADER + " stack trace ";
+
+ /**
+ * End token.
+ */
+ private static final String END = "";
+
+ /**
+ * Nominal width of character display.
+ */
+ private static final int WIDTH = 80;
+
+ /**
+ * Returns the exception and causal exceptions as a formatted string.
+ * @param buffer the string buffer
+ * @param j the causal message sequence
+ * @param message the header message
+ * @param e the exception
+ * @param stack TRUE to generate a stack trace
+ */
+ private static void packException(
+ final StringBuffer buffer, int j, final String message, final
Throwable e, boolean stack )
+ {
+ if( e instanceof Error )
+ {
+ buffer.append( getLine( ERROR, j ) );
+ }
+ else if( e instanceof RuntimeException )
+ {
+ buffer.append( getLine( RUNTIME, j ) );
+ }
+ else
+ {
+ buffer.append( getLine( EXCEPTION, j ) );
+ }
+
+ if( null != message )
+ {
+ buffer.append( message );
+ buffer.append( "\n" );
+ }
+
+ if( e == null )
+ {
+ return;
+ }
+
+ buffer.append( "Exception: " + e.getClass().getName() + "\n" );
+ if( null != e.getMessage() )
+ {
+ buffer.append( "Message: " + e.getMessage() + "\n" );
+ }
+ packCause( buffer, getCause( e ) ).toString();
+ Throwable root = getLastThrowable( e );
+ if( ( root != null ) && stack )
+ {
+ buffer.append( getLine( TRACE ) );
+ String[] trace = captureStackTrace( root );
+ for( int i = 0; i < trace.length; i++ )
+ {
+ buffer.append( trace[i] + "\n" );
+ }
+ }
+ }
+
+ /**
+ * Pack a causal exception.
+ * @param buffer the buffer to pack the exception report
+ * @param cause the causal exception to pack
+ * @return the buffer
+ */
+ private static StringBuffer packCause( StringBuffer buffer, Throwable
cause )
+ {
+ if( cause == null )
+ {
+ return buffer;
+ }
+ buffer.append( getLine( CAUSE ) );
+ buffer.append( "Exception: " + cause.getClass().getName() + "\n" );
+ buffer.append( "Message: " + cause.getMessage() + "\n" );
+ return packCause( buffer, getCause( cause ) );
+ }
+
+ /**
+ * Return the last throwable in the chain.
+ * @param exception the exception to extract the last throwable from
+ * @return the initiating cause
+ */
+ private static Throwable getLastThrowable( Throwable exception )
+ {
+ Throwable cause = getCause( exception );
+ if( cause != null )
+ {
+ return getLastThrowable( cause );
+ }
+ else
+ {
+ return exception;
+ }
+ }
+
+ /**
+ * Get a causal exception using reflection.
+ * @param exception the exception
+ * @return the causal exception
+ */
+ private static Throwable getCause( Throwable exception )
+ {
+ if( null == exception )
+ {
+ return null;
+ }
+
+ try
+ {
+ Class<?> clazz = exception.getClass();
+ Method method = clazz.getMethod( "getCause", new Class<?>[0] );
+ return (Throwable) method.invoke( exception, new Object[0] );
+ }
+ catch( Throwable e )
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Captures the stack trace associated with this exception.
+ *
+ * @param throwable a <code>Throwable</code>
+ * @return an array of Strings describing stack frames.
+ */
+ private static String[] captureStackTrace( final Throwable throwable )
+ {
+ final StringWriter sw = new StringWriter();
+ throwable.printStackTrace( new PrintWriter( sw, true ) );
+ return splitString( sw.toString(), LINE_SEPARATOR );
+ }
+
+ /**
+ * Splits the string on every token into an array of stack frames.
+ *
+ * @param string the string to split
+ * @param onToken the token to split on
+ * @return the resultant array
+ */
+ private static String[] splitString( final String string, final String
onToken )
+ {
+ final int offset = 4;
+ final StringTokenizer tokenizer = new StringTokenizer( string,
onToken );
+ final String[] result = new String[tokenizer.countTokens()];
+
+ for( int i = 0; i < result.length; i++ )
+ {
+ String token = tokenizer.nextToken();
+ if( token.startsWith( "\tat " ) )
+ {
+ result[i] = token.substring( offset );
+ }
+ else
+ {
+ result[i] = token;
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Return a line of '-' characters.
+ * @param lead the lead
+ * @return the line
+ */
+ private static String getLine( String lead )
+ {
+ return getLine( lead, 0 );
+ }
+
+ /**
+ * Get a line of '-' characters with padded offset.
+ * @param lead the leading characters
+ * @param count the number of characters to fill
+ * @return the filled out line
+ */
+ private static String getLine( String lead, int count )
+ {
+ StringBuffer buffer = new StringBuffer( lead );
+ int q = 0;
+ if( count > 0 )
+ {
+ String v = "" + count + " ";
+ buffer.append( "" + count );
+ buffer.append( " " );
+ q = v.length() + 1;
+ }
+ int j = WIDTH - ( lead.length() + q );
+ for( int i=0; i < j; i++ )
+ {
+ buffer.append( "-" );
+ }
+ buffer.append( "\n" );
+ return buffer.toString();
+ }
+
+ /**
+ * Disabled.
+ */
+ private ExceptionHelper()
+ {
+ // disable
+ }
+}

Added: trunk/main/transit/core/src/main/dpml/util/FederatingClassLoader.java
===================================================================
--- trunk/main/transit/core/src/main/dpml/util/FederatingClassLoader.java
2007-02-08 23:39:34 UTC (rev 1832)
+++ trunk/main/transit/core/src/main/dpml/util/FederatingClassLoader.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,327 @@
+/*
+ * Copyright 2005 Stephen J. McConnell.
+ *
+ * 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 dpml.util;
+
+import java.io.IOException;
+import java.rmi.server.RMIClassLoader;
+import java.rmi.server.RMIClassLoaderSpi;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.security.Permission;
+import java.util.Collections;
+import java.util.IdentityHashMap;
+import java.util.Map;
+
+/**
+ * The DepotRMIClassLoaderSpi handles the loading of classes that are based
on
+ * plugin artifact types.
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class FederatingClassLoader extends RMIClassLoaderSpi
+{
+ private static final Map<ClassLoader,Void> LOADERS =
+ Collections.synchronizedMap( new IdentityHashMap<ClassLoader,Void>( 5
) );
+
+ private RMIClassLoaderSpi m_delegate =
RMIClassLoader.getDefaultProviderInstance();
+
+ static
+ {
+ for( ClassLoader classloader = ClassLoader.getSystemClassLoader();
+ classloader != null; classloader = classloader.getParent() )
+ {
+ LOADERS.put( classloader, null );
+ }
+ }
+
+ /**
+ * Default constructor.
+ */
+ public FederatingClassLoader()
+ {
+ super();
+ }
+
+ /**
+ * Provides the implementation for
+ * {@link RMIClassLoader#loadClass(URL,String)},
+ * {@link RMIClassLoader#loadClass(String,String)}, and
+ * {@link RMIClassLoader#loadClass(String,String,ClassLoader)}.
+ *
+ * Loads a class from a codebase URL path, optionally using the
+ * supplied loader.
+ *
+ * @param codebase the list of URLs (separated by spaces) to load
+ * the class from, or <code>null</code>
+ * @param name the name of the class to load
+ * @param defaultLoader additional contextual class loader
+ * to use, or <code>null</code>
+ * @return the <code>Class</code> object representing the loaded class
+ * @exception MalformedURLException if <code>codebase</code> is
+ * non-<code>null</code> and contains an invalid URL, or
+ * if <code>codebase</code> is <code>null</code> and the system
+ * property <code>java.rmi.server.codebase</code> contains an
+ * invalid URL
+ * @exception ClassNotFoundException if a definition for the class
+ * could not be found at the specified location
+ */
+ public Class loadClass(
+ String codebase, String name, ClassLoader defaultLoader )
+ throws MalformedURLException, ClassNotFoundException
+ {
+ //try
+ //{
+ return m_delegate.loadClass( codebase, name, defaultLoader );
+ //}
+ //catch( ClassNotFoundException cnfe )
+ //{
+ // System.out.println( SystemClassLoader.toString( defaultLoader,
null ) );
+ // try
+ // {
+ // Class c = defaultLoader.loadClass( name );
+ // System.out.println( "# FOUND: " + c );
+ // }
+ // catch( ClassNotFoundException e )
+ // {
+ // System.out.println( "# " + e.toString() );
+ // }
+ // throw cnfe;
+ //}
+ }
+
+ /**
+ * Provides the implementation for
+ * {@link RMIClassLoader#loadProxyClass(String,String[],ClassLoader)}.
+ *
+ * Loads a dynamic proxy class (see {@link java.lang.reflect.Proxy}
+ * that implements a set of interfaces with the given names
+ * from a codebase URL path, optionally using the supplied loader.
+ *
+ * <p>An implementation of this method must either return a proxy
+ * class that implements the named interfaces or throw an exception.
+ *
+ * @param codebase the list of URLs (space-separated) to load
+ * classes from, or <code>null</code>
+ * @param interfaces the names of the interfaces for the proxy class
+ * to implement
+ * @param defaultLoader additional contextual class loader
+ * to use, or <code>null</code>
+ * @return a dynamic proxy class that implements the named interfaces
+ * @exception MalformedURLException if <code>codebase</code> is
+ * non-<code>null</code> and contains an invalid URL, or
+ * if <code>codebase</code> is <code>null</code> and the system
+ * property <code>java.rmi.server.codebase</code> contains an
+ * invalid URL
+ * @exception ClassNotFoundException if a definition for one of
+ * the named interfaces could not be found at the specified location,
+ * or if creation of the dynamic proxy class failed (such as if
+ * {@link java.lang.reflect.Proxy#getProxyClass(ClassLoader,Class[])}
+ * would throw an <code>IllegalArgumentException</code> for the given
+ * interface list)
+ */
+ public Class loadProxyClass(
+ String codebase, String[] interfaces, ClassLoader defaultLoader )
+ throws MalformedURLException, ClassNotFoundException
+ {
+ return m_delegate.loadProxyClass( codebase, interfaces,
defaultLoader );
+ }
+
+ /**
+ * Provides the implementation for
+ * {@link RMIClassLoader#getClassLoader(String)}.
+ *
+ * Returns a class loader that loads classes from the given codebase
+ * URL path.
+ *
+ * <p>If there is a security manger, its <code>checkPermission</code>
+ * method will be invoked with a
+ * <code>RuntimePermission("getClassLoader")</code> permission;
+ * this could result in a <code>SecurityException</code>.
+ * The implementation of this method may also perform further security
+ * checks to verify that the calling context has permission to connect
+ * to all of the URLs in the codebase URL path.
+ *
+ * @param codebase the list of URLs (space-separated) from which
+ * the returned class loader will load classes from, or <code>null</code>
+ * @return a class loader that loads classes from the given codebase URL
+ * path
+ * @exception MalformedURLException if <code>codebase</code> is
+ * non-<code>null</code> and contains an invalid URL, or
+ * if <code>codebase</code> is <code>null</code> and the system
+ * property <code>java.rmi.server.codebase</code> contains an
+ * invalid URL
+ * @exception SecurityException if there is a security manager and the
+ * invocation of its <code>checkPermission</code> method fails, or
+ * if the caller does not have permission to connect to all of the
+ * URLs in the codebase URL path
+ */
+ public ClassLoader getClassLoader( String codebase )
+ throws MalformedURLException, SecurityException
+ {
+ return m_delegate.getClassLoader( codebase );
+ }
+
+ /**
+ * Provides the implementation for
+ * {@link RMIClassLoader#getClassAnnotation(Class)}.
+ *
+ * Returns the annotation string (representing a location for
+ * the class definition) that RMI will use to annotate the class
+ * descriptor when marshalling objects of the given class.
+ *
+ * @param cl the class to obtain the annotation for
+ * @return a string to be used to annotate the given class when
+ * it gets marshalled, or <code>null</code>
+ * @exception NullPointerException if <code>cl</code> is <code>null</code>
+ */
+ public String getClassAnnotation( Class cl ) throws NullPointerException
+ {
+ return getAnnotation( cl );
+ }
+
+ private String getAnnotation( Class cl ) throws NullPointerException
+ {
+ String classname = cl.getName();
+ int i = classname.length();
+ if( ( i > 0 ) && classname.charAt( 0 ) == '[' )
+ {
+ int j;
+ for( j=1; i > j && classname.charAt( j ) == '['; j++ )
+ {
+ if( ( i > j ) && classname.charAt( j ) != 'L' )
+ {
+ return null;
+ }
+ }
+ }
+
+ ClassLoader classloader = cl.getClassLoader();
+ if( classloader == null || LOADERS.containsKey( classloader ) )
+ {
+ return System.getProperty( "java.rmi.server.codebase" );
+ }
+
+ String annotations = null;
+ if( classloader instanceof StandardClassLoader )
+ {
+ annotations = ( (StandardClassLoader) classloader
).getAnnotations();
+ }
+ else if( classloader instanceof URLClassLoader )
+ {
+ annotations = getAnnotations( (URLClassLoader) classloader );
+ }
+
+ if( annotations != null )
+ {
+ return annotations;
+ }
+ else
+ {
+ return System.getProperty( "java.rmi.server.codebase" );
+ }
+ }
+
+ private String getAnnotations( URLClassLoader classloader )
+ {
+ StringBuffer buffer = new StringBuffer();
+ return getAnnotations( buffer, classloader );
+ }
+
+ private String getAnnotations( StringBuffer buffer, URLClassLoader
classloader )
+ {
+ packAnnotations( buffer, classloader );
+ String result = buffer.toString();
+ return result.trim();
+ }
+
+ private void packAnnotations( StringBuffer buffer, URLClassLoader
classloader )
+ {
+ if( ClassLoader.getSystemClassLoader() == classloader )
+ {
+ return;
+ }
+
+ ClassLoader parent = classloader.getParent();
+ if( ( null != parent ) && ( parent instanceof URLClassLoader ) )
+ {
+ packAnnotations( buffer, (URLClassLoader) parent );
+ }
+
+ try
+ {
+ URL[] urls = classloader.getURLs();
+ if( null != urls )
+ {
+ SecurityManager manager = System.getSecurityManager();
+ if( manager != null )
+ {
+ for( int k = 0; k < urls.length; k++ )
+ {
+ Permission permission =
urls[k].openConnection().getPermission();
+ if( permission != null )
+ {
+ manager.checkPermission( permission );
+ }
+ }
+ }
+ buffer.append( urlsToPath( urls ) + " " );
+ }
+ }
+ catch( SecurityException e )
+ {
+ boolean ignore = true; // ignore
+ }
+ catch( IOException e )
+ {
+ boolean ignore = true; // ignore
+ }
+ }
+
+ private static String urlsToPath( URL[] urls )
+ {
+ if( urls.length == 0 )
+ {
+ return null;
+ }
+ else if( urls.length == 1 )
+ {
+ final String path = urls[0].toExternalForm();
+ if( !path.startsWith( "file:" ) )
+ {
+ return path;
+ }
+ else
+ {
+ return "";
+ }
+ }
+ StringBuffer buffer = new StringBuffer( urls[0].toExternalForm() );
+ for( int i=1; i < urls.length; i++ )
+ {
+ final String path = urls[i].toExternalForm();
+ if( !path.startsWith( "file:" ) )
+ {
+ buffer.append( ' ' );
+ buffer.append( path );
+ }
+ }
+ return buffer.toString();
+ }
+}

Added: trunk/main/transit/core/src/main/dpml/util/LogStatement.java
===================================================================
--- trunk/main/transit/core/src/main/dpml/util/LogStatement.java
2007-02-08 23:39:34 UTC (rev 1832)
+++ trunk/main/transit/core/src/main/dpml/util/LogStatement.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2006 Stephen McConnell.
+ *
+ * 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 dpml.util;
+
+import java.io.Serializable;
+import java.util.logging.LogRecord;
+
+/**
+ * Datastructure holding a log record and process identifier. The
datastructure
+ * is used to bind a PID value that identifies a source JVM with a log
record
+ * raised by the JVM.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public final class LogStatement implements Serializable
+{
+ /**
+ * Serial version identifier.
+ */
+ static final long serialVersionUID = 1L;
+
+ private final PID m_pid;
+ private final LogRecord m_record;
+
+ /**
+ * Creation of a new log statement.
+ * @param pid the JVM process identifier
+ * @param record the log record
+ */
+ public LogStatement( PID pid, LogRecord record )
+ {
+ m_pid = pid;
+ m_record = record;
+ }
+
+ /**
+ * Get the process identifier identifying the source JVM.
+ * @return the process identifier
+ */
+ public PID getPID()
+ {
+ return m_pid;
+ }
+
+ /**
+ * Get the log record raised by the source JVM.
+ * @return the log record
+ */
+ public LogRecord getLogRecord()
+ {
+ return m_record;
+ }
+
+ /**
+ * Compare this object with a supplied object for equality.
+ * This function returns true if the supplied object is a
+ * LogStatement with an equivalent process identifier and
+ * log record.
+ * @param other the other object
+ * @return true if the supplied object is equal to this object
+ */
+ public boolean equals( Object other )
+ {
+ if( null == other )
+ {
+ return false;
+ }
+ else if( other instanceof LogStatement )
+ {
+ LogStatement statement = (LogStatement) other;
+ if( !m_pid.equals( statement.m_pid ) )
+ {
+ return false;
+ }
+ else
+ {
+ return m_record.equals( statement.m_record );
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Get the hascode for this instance.
+ * @return the instance hash value
+ */
+ public int hashCode()
+ {
+ int hash = m_pid.hashCode();
+ hash ^= m_record.hashCode();
+ return hash;
+ }
+}
+

Copied: trunk/main/transit/core/src/main/dpml/util/LoggingService.java (from
rev 1789, trunk/main/transit/core/src/main/net/dpml/util/LoggingService.java)
===================================================================
--- trunk/main/transit/core/src/main/net/dpml/util/LoggingService.java
2006-11-30 21:08:46 UTC (rev 1789)
+++ trunk/main/transit/core/src/main/dpml/util/LoggingService.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2005-2007 Stephen McConnell.
+ *
+ * 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 dpml.util;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.logging.LogRecord;
+
+/**
+ * Interface exposed by a remote logging service to local log aggregation
handlers.
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public interface LoggingService extends Remote
+{
+ /**
+ * Logging service key.
+ */
+ String LOGGING_KEY = "dpml/logging";
+
+ /**
+ * Register a log record with the log service.
+ * @param process the process identifier
+ * @param record the log record
+ * @exception RemoteException if a remote exception occurs
+ */
+ void log( PID process, LogRecord record ) throws RemoteException;
+}
+

Added: trunk/main/transit/core/src/main/dpml/util/Main.java
===================================================================
--- trunk/main/transit/core/src/main/dpml/util/Main.java 2007-02-08
23:39:34 UTC (rev 1832)
+++ trunk/main/transit/core/src/main/dpml/util/Main.java 2007-02-08
23:42:59 UTC (rev 1833)
@@ -0,0 +1,413 @@
+/*
+ * Copyright 2005 Stephen J. McConnell.
+ *
+ * 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 dpml.util;
+
+import dpml.transit.StandardMonitor;
+import dpml.util.DefaultLogger;
+import dpml.util.PropertyResolver;
+import dpml.util.CLIHelper;
+import dpml.util.PID;
+
+import java.io.File;
+import java.net.URI;
+import java.net.URL;
+import java.rmi.RMISecurityManager;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.logging.LogManager;
+import java.util.Properties;
+
+import javax.tools.Tool;
+
+//import net.dpml.lang.Strategy;
+
+import net.dpml.transit.Transit;
+import net.dpml.transit.Artifact;
+
+import net.dpml.util.Logger;
+
+import static net.dpml.transit.Transit.VERSION;
+
+/**
+ * CLI hander for the depot package.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public final class Main
+{
+ private static Main m_MAIN;
+ private static final PID PROCESS_ID = new PID();
+
+ private Object m_plugin;
+ private boolean m_debug = false;
+ private boolean m_trace = false;
+
+ /**
+ * Processes command line options to establish the command handler plugin
to deploy.
+ * Command parameters recognixed by the console include the following:
+ * <ul>
+ * <li>-Ddpml.depot.application=[uri]</li>
+ * <li>-debug</li>
+ * </ul>
+ * @param args the command line argument array
+ * @exception Exception if a error occurs
+ */
+ public static void main( String[] args )
+ throws Exception
+ {
+ if( null != m_MAIN )
+ {
+ final String error =
+ "Console already established.";
+ throw new IllegalArgumentException( error );
+ }
+ else
+ {
+ m_MAIN = new Main( args );
+ }
+ }
+
+ private Main( String[] arguments )
+ {
+ String[] args = processSystemProperties( arguments );
+
+ ClassLoader system = ClassLoader.getSystemClassLoader();
+ Thread.currentThread().setContextClassLoader( system );
+
+ //
+ // check for debug and trace cli options
+ //
+
+
+ if( CLIHelper.isOptionPresent( args, "-trace" ) )
+ {
+ args = CLIHelper.consolidate( args, "-trace" );
+ System.setProperty( "dpml.trace", "true" );
+ m_trace = true;
+ }
+
+ if( CLIHelper.isOptionPresent( args, "-debug" ) )
+ {
+ args = CLIHelper.consolidate( args, "-debug" );
+ System.setProperty( "dpml.debug", "true" );
+ m_debug = true;
+ }
+
+ //
+ // handle cli sub-system establishment
+ //
+
+ String path = System.getProperty( APPLICATION_KEY, null );
+ if( null == path )
+ {
+ System.out.println( "Undefined system property '" +
APPLICATION_KEY + "'." );
+ System.exit( -1 );
+ }
+
+ if( null == System.getProperty( "dpml.logging.config" ) )
+ {
+ if( m_trace )
+ {
+ setSystemProperty( "dpml.logging.config",
"local:properties:dpml/transit/trace" );
+ }
+ else if( m_debug )
+ {
+ System.setProperty( "dpml.logging.config",
"local:properties:dpml/transit/debug" );
+ }
+ else
+ {
+ System.setProperty( "dpml.logging.config",
"local:properties:dpml/transit/default" );
+ }
+ }
+
+ if( m_trace )
+ {
+ for( int i=0; i<arguments.length; i++ )
+ {
+ getLogger().debug( "arg[" + i + "]: " + arguments[i] );
+ }
+
+ int id = System.identityHashCode( system );
+
+ getLogger().trace( system.toString() );
+ }
+ final int exit = deployHandler( path, args, false );
+ if( exit < 1 )
+ {
+ if( getLogger().isTraceEnabled() )
+ {
+ getLogger().trace( "exit " + exit );
+ }
+ Thread thread = new Thread(
+ new Runnable()
+ {
+ public void run()
+ {
+ System.exit( exit );
+ }
+ }
+ );
+ thread.start();
+ }
+ else
+ {
+ if( getLogger().isTraceEnabled() )
+ {
+ getLogger().trace( "joining" );
+ }
+ try
+ {
+ Thread.currentThread().join();
+ }
+ catch( InterruptedException e )
+ {
+ if( getLogger().isTraceEnabled() )
+ {
+ getLogger().info( "exit/interrupt" );
+ }
+ }
+ finally
+ {
+ if( getLogger().isTraceEnabled() )
+ {
+ getLogger().info( "exit " + exit );
+ }
+ Thread thread = new Thread(
+ new Runnable()
+ {
+ public void run()
+ {
+ System.exit( exit );
+ }
+ }
+ );
+ thread.start();
+ }
+ }
+ }
+
+ private int deployHandler(
+ String path, String[] args, boolean waitFor )
+ {
+ System.setSecurityManager( new RMISecurityManager() );
+ Logger logger = getLogger();
+ if( logger.isTraceEnabled() )
+ {
+ logger.trace( "date: " + new Date() );
+ logger.trace( "uri: " + path );
+ logger.trace( "args: [" + toString( args ) + "]" );
+ logger.trace( "system classloader: ["
+ + System.identityHashCode( ClassLoader.getSystemClassLoader()
)
+ + "]" );
+ }
+ Logger log = resolveLogger( logger );
+ try
+ {
+ URI uri = new URI( path );
+ Transit transit = Transit.getInstance();
+ transit.addMonitor( new StandardMonitor( logger ) );
+
+ //
+ // implementation is limited to uris recognized as artifacts that
+ // resolve to a javax.tools.Tool implementation
+ //
+
+ if( Artifact.isRecognized( uri ) )
+ {
+ URL url = Artifact.toURL( uri );
+ Tool tool = (Tool) url.getContent( new Class[]{ Tool.class }
);
+ if( null == tool )
+ {
+ final String error =
+ "The target uri ["
+ + uri
+ + "] did not return a value for the content class ["
+ + Tool.class.getName()
+ + "].";
+ logger.error( error );
+ return -1;
+ }
+ //ClassLoader system = ClassLoader.getSystemClassLoader();
+ //Tool tool = Strategy.load( system, Tool.class, uri, null );
+ return tool.run( null, null, null, args );
+ }
+ else
+ {
+ final String error =
+ "URI scheme not recognized ["
+ + uri
+ + "]";
+ logger.error( error );
+ return -1;
+ }
+ }
+ catch( Throwable e )
+ {
+ e.printStackTrace();
+ return -1;
+ }
+ }
+
+ private Logger resolveLogger( Logger logger )
+ {
+ String partition = System.getProperty( "dpml.station.partition",
null );
+ if( null != partition )
+ {
+ return new DefaultLogger( partition );
+ }
+ else
+ {
+ return logger;
+ }
+ }
+
+ private static Logger getLogger()
+ {
+ if( null == m_LOGGER )
+ {
+ try
+ {
+ LogManager.getLogManager().readConfiguration();
+ }
+ catch( Throwable e )
+ {
+ e.printStackTrace();
+ }
+ String category = System.getProperty( "dpml.logging.category",
"dpml.lang" );
+ m_LOGGER = new DefaultLogger(
java.util.logging.Logger.getLogger( category ) );
+ }
+ return m_LOGGER;
+ }
+
+ private String toString( String[] args )
+ {
+ StringBuffer buffer = new StringBuffer();
+ for( int i=0; i<args.length; i++ )
+ {
+ if( i > 0 )
+ {
+ buffer.append( ", " );
+ }
+ buffer.append( args[i] );
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * For all of the supplied command line arguments, if the
+ * argument is in the form -Dabc=def then extract the argument from
+ * the array and apply it as a system property. All non-system property
+ * arguments are included in the returned argument array.
+ *
+ * @param args the supplied commandline arguments including
+ * system property assignments
+ * @return the array of pure command line arguments (excluding
+ * and arg values recognized as system property declarations
+ */
+ private String[] processSystemProperties( String[] args )
+ {
+ ArrayList<String> result = new ArrayList<String>();
+ for( int i=0; i < args.length; i++ )
+ {
+ String arg = args[i];
+ int index = arg.indexOf( "=" );
+ if( index > -1 && arg.startsWith( "-D" ) )
+ {
+ String name = arg.substring( 2, index );
+ String raw = arg.substring( index + 1 );
+ Properties system = System.getProperties();
+ String value = PropertyResolver.resolve( system, raw );
+ System.setProperty( name, value );
+ }
+ else
+ {
+ result.add( arg );
+ }
+ }
+ return result.toArray( new String[0] );
+ }
+
+
//--------------------------------------------------------------------------
+ // static utilities for setup of logging manager and root prefs
+
//--------------------------------------------------------------------------
+
+ /**
+ * Create a shutdown hook that will trigger shutdown of the supplied
plugin.
+ * @param thread the application thread
+ */
+ public static void setShutdownHook( final Thread thread )
+ {
+ //
+ // Create a shutdown hook to trigger clean disposal of the
+ // controller
+ //
+
+ Runtime.getRuntime().addShutdownHook(
+ new Thread()
+ {
+ public void run()
+ {
+ try
+ {
+ thread.interrupt();
+ }
+ catch( Throwable e )
+ {
+ boolean ignorable = true;
+ }
+ System.runFinalization();
+ }
+ }
+ );
+ }
+
+ /**
+ * DPML build key.
+ */
+ private static final String BUILD_KEY = "dpml.build";
+
+ /**
+ * The Depot system version.
+ */
+ private static final String BUILD_ID = "@BUILD-ID@";
+
+ static
+ {
+ setSystemProperty( "java.util.logging.config.class",
"dpml.util.ConfigurationHandler" );
+ setSystemProperty( "java.rmi.server.RMIClassLoaderSpi",
"dpml.util.FederatingClassLoader" );
+ setSystemProperty( BUILD_KEY, BUILD_ID );
+ }
+
+ private static void setSystemProperty( String key, String value )
+ {
+ if( null == System.getProperty( key ) )
+ {
+ System.setProperty( key, value );
+ }
+ }
+
+ private static Logger m_LOGGER = null;
+
+ /**
+ * Application selection key.
+ */
+ public static final String APPLICATION_KEY = "dpml.depot.application";
+}
+

Added: trunk/main/transit/core/src/main/dpml/util/ObjectUtils.java
===================================================================
--- trunk/main/transit/core/src/main/dpml/util/ObjectUtils.java 2007-02-08
23:39:34 UTC (rev 1832)
+++ trunk/main/transit/core/src/main/dpml/util/ObjectUtils.java 2007-02-08
23:42:59 UTC (rev 1833)
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2007 Stephen J. McConnell
+ *
+ * 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 dpml.util;
+
+/**
+ * Object equality and hashcode utilities.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class ObjectUtils
+{
+ private ObjectUtils()
+ {
+ }
+
+ /**
+ * Utility to hash an array.
+ * @param array the array
+ * @return the hash value
+ */
+ public static int hashArray( Object[] array )
+ {
+ if( null == array )
+ {
+ return 0;
+ }
+ int hash = 0;
+ for( Object object : array )
+ {
+ hash ^= hashValue( object );
+ }
+ return hash;
+ }
+
+ /**
+ * Utility to hash an object.
+ * @param value the object
+ * @return the hash value
+ */
+ public static int hashValue( Object value )
+ {
+ if( null == value )
+ {
+ return 0;
+ }
+ else if( value instanceof Object[] )
+ {
+ return hashArray( (Object[]) value );
+ }
+ else
+ {
+ return value.hashCode();
+ }
+ }
+
+ /**
+ * Utility to compare two object for equality.
+ * @param a the first object
+ * @param b the second object
+ * @return true if the objects are equal
+ */
+ public static boolean equals( Object a, Object b )
+ {
+ if( null == a )
+ {
+ return ( null == b );
+ }
+ else
+ {
+ return a.equals( b );
+ }
+ }
+}

Added: trunk/main/transit/core/src/main/dpml/util/PID.java
===================================================================
--- trunk/main/transit/core/src/main/dpml/util/PID.java 2007-02-08 23:39:34
UTC (rev 1832)
+++ trunk/main/transit/core/src/main/dpml/util/PID.java 2007-02-08 23:42:59
UTC (rev 1833)
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2005-2007 Stephen J. McConnell.
+ *
+ * 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 dpml.util;
+
+import java.io.Serializable;
+
+import java.util.Random;
+
+/**
+ * The PID class is a process identifer.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class PID implements Serializable
+{
+ private final int m_value;
+
+ /**
+ * Creation of a new process identifier.
+ */
+ public PID()
+ {
+ m_value = setupInitialValue();
+ }
+
+ /**
+ * Creation of a new process identifier.
+ */
+ private PID( int id )
+ {
+ m_value = id;
+ }
+
+ private static int setupInitialValue()
+ {
+ String id = System.getProperty( "process.id" );
+ if( null == id )
+ {
+ return Math.abs( new Random().nextInt() );
+ }
+ else
+ {
+ try
+ {
+ return Integer.parseInt( id );
+ }
+ catch( NumberFormatException e )
+ {
+ return Math.abs( new Random().nextInt() );
+ }
+ }
+ }
+
+ /**
+ * Return the process identifier int value.
+ * @return the process id value
+ */
+ public int getValue()
+ {
+ return m_value;
+ }
+
+ /**
+ * Return the string representation of this process identifier.
+ * @return the process identifier as a string
+ */
+ public String toString()
+ {
+ return "[" + m_value + "]";
+ }
+
+ /**
+ * Test if a supplied object is equal to this process identifier.
+ * @param other the object to compare with this object
+ * @return TRUE if the objects are equivalent
+ */
+ public boolean equals( Object other )
+ {
+ if( other instanceof PID )
+ {
+ PID pid = (PID) other;
+ return getValue() == pid.getValue();
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Return the hashcode for this PID instance.
+ * @return the hashcode value
+ */
+ public int hashCode()
+ {
+ return getValue();
+ }
+}
+

Copied: trunk/main/transit/core/src/main/dpml/util/PropertyResolver.java
(from rev 1789,
trunk/main/transit/core/src/main/net/dpml/util/PropertyResolver.java)
===================================================================
--- trunk/main/transit/core/src/main/net/dpml/util/PropertyResolver.java
2006-11-30 21:08:46 UTC (rev 1789)
+++ trunk/main/transit/core/src/main/dpml/util/PropertyResolver.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2006-2007 Stephen McConnell
+ * Copyright 2004 Niclas Hedhman
+ *
+ * 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 dpml.util;
+
+import java.util.Enumeration;
+import java.util.Properties;
+import java.util.Stack;
+import java.util.StringTokenizer;
+
+import net.dpml.transit.Transit;
+
+/**
+ * Utility class that handles substitution of property names in the string
+ * for ${value} relative to a supplied set of properties.
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public final class PropertyResolver
+{
+ //
------------------------------------------------------------------------
+ // static
+ //
------------------------------------------------------------------------
+
+ static
+ {
+ Object s = Transit.DATA;
+ }
+
+ /**
+ * System property symbol substitution from properties.
+ * Replace any occurances of ${[key]} with the value of the property
+ * assigned to the [key] in the system properties or supplied properties.
+ * @param base base property defintion
+ * @param properties an arbitary properties file containing unresolved
properties
+ * @return the property file with expended properties
+ */
+ public static Properties resolve( Properties base, Properties properties
)
+ {
+ Properties props = new Properties();
+ Enumeration names = properties.propertyNames();
+ while( names.hasMoreElements() )
+ {
+ String name = (String) names.nextElement();
+ String old = properties.getProperty( name );
+ String value = resolve( base, old );
+ String v2 = resolve( properties, value );
+ props.setProperty( name, v2 );
+ }
+ return props;
+ }
+
+ /**
+ * Symbol substitution from properties.
+ * Replace any occurances of ${[key]} with the value of the property
+ * assigned to the [key] in the supplied properties argument.
+ * @param props the source properties from which substitution is resolved
+ * @param value a string containing possibly multiple ${[value]} sequences
+ * @return the expanded string
+ */
+ public static String resolve( Properties props, String value )
+ {
+ if( value == null )
+ {
+ return null;
+ }
+
+ // optimization for common case.
+ if( value.indexOf( '$' ) < 0 )
+ {
+ return value;
+ }
+ int pos1 = value.indexOf( "${" );
+ if( pos1 < 0 )
+ {
+ return value;
+ }
+
+ Stack<String> stack = new Stack<String>();
+ StringTokenizer st = new StringTokenizer( value, "${}", true );
+
+ while ( st.hasMoreTokens() )
+ {
+ String token = st.nextToken();
+ if( token.equals( "}" ) )
+ {
+ String name = (String) stack.pop();
+ String open = (String) stack.pop();
+ if( open.equals( "$${" ) )
+ {
+ push( stack, "${" + name + "}" );
+ }
+ else if( open.equals( "${" ) )
+ {
+ String propValue = System.getProperty( name );
+ if( ( propValue == null ) && ( null != props ) )
+ {
+ propValue = props.getProperty( name );
+ }
+ if( propValue == null )
+ {
+ push( stack, "${" + name + "}" );
+ }
+ else
+ {
+ push( stack, propValue );
+ }
+ }
+ else
+ {
+ push( stack, "${" + name + "}" );
+ }
+ }
+ else
+ {
+ if( token.equals( "$" ) )
+ {
+ String peek = peek( stack );
+ if( "$".equals( peek ) )
+ {
+ stack.push( "$$" );
+ }
+ else
+ {
+ stack.push( "$" );
+ }
+ }
+ else
+ {
+ push( stack, token );
+ }
+ }
+ }
+ String result = "";
+ while ( stack.size() > 0 )
+ {
+ result = stack.pop() + result;
+ }
+ return result;
+ }
+
+ private static String peek( Stack<String> stack )
+ {
+ try
+ {
+ return stack.peek();
+ }
+ catch( Exception e )
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Pushes a value on a stack
+ * @param stack the stack
+ * @param value the value
+ */
+ private static void push( Stack<String> stack , String value )
+ {
+ if( stack.size() > 0 )
+ {
+ String data = (String) stack.pop();
+ if( data.equals( "$" ) && !"{".equals( value ) )
+ {
+ stack.push( value );
+ }
+ else if( data.equals( "${" ) )
+ {
+ stack.push( data );
+ stack.push( value );
+ }
+ else if( data.equals( "$${" ) )
+ {
+ stack.push( value );
+ }
+ else
+ {
+ stack.push( data + value );
+ }
+ }
+ else
+ {
+ stack.push( value );
+ }
+ }
+
+ //
------------------------------------------------------------------------
+ // constructor
+ //
------------------------------------------------------------------------
+
+ /**
+ * Null constructor.
+ */
+ private PropertyResolver()
+ {
+ }
+}
+

Copied: trunk/main/transit/core/src/main/dpml/util/SimpleResolver.java (from
rev 1789, trunk/main/transit/core/src/main/net/dpml/util/SimpleResolver.java)
===================================================================
--- trunk/main/transit/core/src/main/net/dpml/util/SimpleResolver.java
2006-11-30 21:08:46 UTC (rev 1789)
+++ trunk/main/transit/core/src/main/dpml/util/SimpleResolver.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2006-2007 Stephen J. McConnell.
+ *
+ * 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 dpml.util;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Properties;
+
+import net.dpml.util.Resolver;
+
+/**
+ * Build-time value resolver.
+ */
+public class SimpleResolver implements Resolver
+{
+ /**
+ * Utility function supporting resolution of uris containing 'resource'
or
+ * 'alias' schemes. If the supplied uri scheme is 'resource' or 'alias'
the
+ * reference is resolved to a artifact type, group and name from which a
+ * resource is resolved and the uri returned. If the scheme is resource
+ * the usi of the resource is returned. If the scheme is 'alias' a
+ * link alias is returned. If the scheme is not 'resource' or 'alias'
+ * the argument will be evaluated as a normal transit artifact uri
+ * specification.
+ *
+ * @param ref the uri argument
+ * @return the uri value
+ * @exception URISyntaxException if an error occurs during uri creation
+ */
+ public URI toURI( String ref ) throws URISyntaxException
+ {
+ String value = resolve( ref );
+ return new URI( value );
+ }
+
+ /**
+ * Return a property value.
+ * @param key the property key
+ * @return the property value
+ */
+ public String getProperty( String key )
+ {
+ return System.getProperty( key );
+ }
+
+ /**
+ * Return a property value.
+ * @param key the property key
+ * @param value the default value
+ * @return the property value
+ */
+ public String getProperty( String key, String value )
+ {
+ return System.getProperty( key, value );
+ }
+
+ /**
+ * Symbolic expansion of a supplied value.
+ * Replace any occurances of ${[key]} with the value of the property
+ * assigned to the [key] in system properties.
+ * @param value a string containing possibly multiple ${[value]} sequences
+ * @return the expanded string
+ */
+ public String resolve( String value )
+ {
+ Properties properties = System.getProperties();
+ return PropertyResolver.resolve( properties, value );
+ }
+}

Added: trunk/main/transit/core/src/main/dpml/util/StandardClassLoader.java
===================================================================
--- trunk/main/transit/core/src/main/dpml/util/StandardClassLoader.java
2007-02-08 23:39:34 UTC (rev 1832)
+++ trunk/main/transit/core/src/main/dpml/util/StandardClassLoader.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,548 @@
+/*
+ * Copyright (c) 2005 Stephen J. McConnell
+ *
+ * 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 dpml.util;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.net.URL;
+import java.net.URI;
+import java.net.URLClassLoader;
+
+import net.dpml.transit.Artifact;
+
+import net.dpml.util.Logger;
+
+/**
+ * A named classloader.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class StandardClassLoader extends URLClassLoader
+{
+ //--------------------------------------------------------------------
+ // static
+ //--------------------------------------------------------------------
+
+ /**
+ * Internal utility class to build a classloader. If the supplied url
+ * sequence is zero length the parent classloader is returned directly.
+ *
+ * @param logger the logging channel
+ * @param name the name identifying the classloader
+ * @param category the category that this classloader is handling
+ * @param parent the parent classloader
+ * @param uris the uris to assign as classloader content
+ * @return the classloader
+ * @exception IOException if an I/O error occurs
+ */
+ public static ClassLoader buildClassLoader( Logger logger, String name,
Category category, ClassLoader parent, URI[] uris )
+ throws IOException
+ {
+ URL[] urls = toURLs( uris );
+ if( 0 == urls.length )
+ {
+ return parent;
+ }
+ ArrayList<URL> list = new ArrayList<URL>();
+ for( int i=0; i < urls.length; i++ )
+ {
+ if( isaCandidate( parent, urls[i] ) )
+ {
+ list.add( urls[i] );
+ }
+ }
+ URL[] qualified = (URL[]) list.toArray( new URL[0] );
+ if( qualified.length == 0 )
+ {
+ return parent;
+ }
+ else
+ {
+ ClassLoader loader =
+ new StandardClassLoader( name, category, qualified, parent );
+ classloaderConstructed( logger, name, category, loader );
+ return loader;
+ }
+ }
+
+ /**
+ * Convert a sequence of URIs to URLs.
+ * @param uris the uris to convert
+ * @return the corresponding urls
+ * @exception IOException of a transformation error occurs
+ */
+ public static URL[] toURLs( URI[] uris ) throws IOException
+ {
+ URL[] urls = new URL[ uris.length ];
+ for( int i=0; i < urls.length; i++ )
+ {
+ URI uri = uris[i];
+ if( Artifact.isRecognized( uri ) )
+ {
+ urls[i] = Artifact.toURL( uri );
+ }
+ else
+ {
+ urls[i] = uri.toURL();
+ }
+ }
+ return urls;
+ }
+
+ /**
+ * Test if the supplied url is already present within the supplied
classloader.
+ * @param classloader the classloader to validate against
+ * @param url to url to check for
+ * @return true if the url is not included in the classloader
+ */
+ private static boolean isaCandidate( ClassLoader classloader, URL url )
+ {
+ if( classloader instanceof URLClassLoader )
+ {
+ URL[] urls = ( (URLClassLoader) classloader ).getURLs();
+ for( int i=0; i < urls.length; i++ )
+ {
+ if( urls[i].equals( url ) )
+ {
+ return false;
+ }
+ }
+ ClassLoader parent = classloader.getParent();
+ if( parent == null )
+ {
+ return true;
+ }
+ else
+ {
+ return isaCandidate( parent, url );
+ }
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+ //--------------------------------------------------------------------
+ // state
+ //--------------------------------------------------------------------
+
+ private final Category m_category;
+ private final String m_name;
+
+ //--------------------------------------------------------------------
+ // constructor
+ //--------------------------------------------------------------------
+
+ /**
+ * Creation of a new classloader.
+ * @param name a name identifying the plugin
+ * @param category the classloader category identifier
+ * @param urls an array of urls to add to the classloader
+ * @param parent the parent classloader
+ */
+ public StandardClassLoader( String name, Category category, URL[] urls,
ClassLoader parent )
+ {
+ super( urls, parent );
+ m_category = category;
+ m_name = name;
+ }
+
+ //--------------------------------------------------------------------
+ // StandardClassLoader
+ //--------------------------------------------------------------------
+
+ /**
+ * Return the classloader category
+ * @return the classloader category
+ */
+ public Category getCategory()
+ {
+ return m_category;
+ }
+
+ /**
+ * Return a string representation of the classloader.
+ * @return the string value
+ */
+ public String getAnnotations()
+ {
+ StringBuffer buffer = new StringBuffer();
+ ClassLoader parent = getParent();
+ if( parent instanceof URLClassLoader )
+ {
+ URLClassLoader urlClassLoader = (URLClassLoader) parent;
+ buffer.append( getURLClassLoaderAnnotations( urlClassLoader ) );
+ }
+ buffer.append( " " );
+ URL[] urls = getURLs();
+ for( int i=0; i<urls.length; i++ )
+ {
+ String path = urls[i].toString();
+ if( !path.startsWith( "file:" ) )
+ {
+ buffer.append( path );
+ buffer.append( " " );
+ }
+ }
+ return buffer.toString().trim();
+ }
+
+ private String getURLClassLoaderAnnotations( URLClassLoader classloader )
+ {
+ StringBuffer buffer = new StringBuffer();
+ ClassLoader parent = classloader.getParent();
+ if( ( null != parent ) && ( parent instanceof URLClassLoader ) )
+ {
+ URLClassLoader urlClassLoader = (URLClassLoader) parent;
+ buffer.append( getURLClassLoaderAnnotations( urlClassLoader ) );
+ }
+ if( ClassLoader.getSystemClassLoader() == classloader )
+ {
+ return "";
+ }
+ buffer.append( " " );
+ URL[] urls = classloader.getURLs();
+ for( int i=0; i<urls.length; i++ )
+ {
+ String path = urls[i].toString();
+ if( !path.startsWith( "file:" ) )
+ {
+ buffer.append( path );
+ buffer.append( " " );
+ }
+ }
+ return buffer.toString().trim();
+ }
+
+ //--------------------------------------------------------------------
+ // Object
+ //--------------------------------------------------------------------
+
+ /**
+ * Return a string representing of the classloader.
+ * @return the string representation
+ */
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer();
+ listClasspath( buffer );
+ return buffer.toString();
+ }
+
+ /**
+ * Internal operation to list the classloader classpath.
+ * @param buffer the buffer to list to
+ */
+ protected void listClasspath( StringBuffer buffer )
+ {
+ listClasspath( buffer, this );
+ buffer.append( "\n" );
+ }
+
+ /**
+ * Internal operation to list a classloader classpath.
+ * @param buffer the buffer to list to
+ * @param classloader the classloader to list
+ */
+ protected void listClasspath( StringBuffer buffer, ClassLoader
classloader )
+ {
+ String label =
+ "\nClassLoader: "
+ + classloader.getClass().getName()
+ + " ("
+ + System.identityHashCode( classloader )
+ + ")";
+
+ if( classloader instanceof StandardClassLoader )
+ {
+ StandardClassLoader cl = (StandardClassLoader) classloader;
+ ClassLoader parent = cl.getParent();
+ if( null != parent )
+ {
+ listClasspath( buffer, parent );
+ }
+
+ if( null != m_name )
+ {
+ label = label.concat( "\nLabel: " + cl.m_name + " " +
cl.getCategory() );
+ }
+ else
+ {
+ label = label.concat( "\nCategory: " + cl.getCategory() );
+ }
+ buffer.append( label );
+ buffer.append( "\n" );
+ appendEntries( buffer, cl );
+ }
+ else if( classloader instanceof URLClassLoader )
+ {
+ URLClassLoader cl = (URLClassLoader) classloader;
+ ClassLoader parent = cl.getParent();
+ if( null != parent )
+ {
+ listClasspath( buffer, parent );
+ }
+ buffer.append( label );
+ appendEntries( buffer, cl );
+ }
+ else
+ {
+ buffer.append( label );
+ buffer.append( "]\n" );
+ }
+ }
+
+ private static void appendEntries( StringBuffer buffer, URLClassLoader
classloader )
+ {
+ URL[] urls = classloader.getURLs();
+ for( int i=0; i < urls.length; i++ )
+ {
+ buffer.append( "\n " );
+ URL url = urls[i];
+ String spec = url.toString();
+ buffer.append( spec );
+ }
+ buffer.append( "\n" );
+ }
+
+ public static String toString( Class clazz )
+ {
+ ClassLoader anchor = clazz.getClassLoader();
+ return toString( anchor );
+ }
+
+ public static String toString( ClassLoader anchor )
+ {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(
"\n----------------------------------------------------------------" );
+ buffer.append( "\nClassloader: " + System.identityHashCode( anchor )
);
+ buffer.append(
"\n----------------------------------------------------------------" );
+ list( buffer, anchor );
+ buffer.append(
"\n----------------------------------------------------------------" );
+ return buffer.toString();
+ }
+
+ public static String toString( Class primary, Class secondary )
+ {
+ if( null == primary )
+ {
+ throw new NullPointerException( "primary" );
+ }
+ if( null == secondary )
+ {
+ throw new NullPointerException( "secondary" );
+ }
+ return toString( primary.getClassLoader(),
secondary.getClassLoader() );
+ }
+
+ /**
+ * Return a string representing a report fo the common classloader chain
+ * following by the primary annd seciondarty classloaders.
+ * @param primary the primary classloader
+ * @param secondary the secondary classloader
+ * @return the report
+ */
+ public static String toString( ClassLoader primary, ClassLoader
secondary )
+ {
+ StringBuffer buffer = new StringBuffer();
+ ClassLoader anchor = getCommonParent( primary, secondary );
+ if( null != anchor )
+ {
+ buffer.append(
"\n----------------------------------------------------------------" );
+ buffer.append( "\nCommon Classloader: " +
System.identityHashCode( anchor ) );
+ buffer.append(
"\n----------------------------------------------------------------" );
+ list( buffer, anchor );
+ }
+ if( ( null != primary ) && ( primary != anchor ) )
+ {
+ buffer.append(
"\n----------------------------------------------------------------" );
+ buffer.append( "\nPrimary Classloader: " +
System.identityHashCode( primary ) );
+ buffer.append( " extends " + System.identityHashCode(
primary.getParent() ) );
+ buffer.append(
"\n----------------------------------------------------------------" );
+ list( buffer, primary, anchor );
+ }
+ if( ( null != secondary ) && ( secondary != anchor ) )
+ {
+ buffer.append(
"\n----------------------------------------------------------------" );
+ buffer.append( "\nSecondary Classloader: " +
System.identityHashCode( secondary ) );
+ buffer.append( " extends " + System.identityHashCode(
secondary.getParent() ) );
+ buffer.append(
"\n----------------------------------------------------------------" );
+ list( buffer, secondary, anchor );
+ }
+ buffer.append(
"\n----------------------------------------------------------------" );
+ return buffer.toString();
+ }
+
+ private static ClassLoader getCommonParent( ClassLoader primary,
ClassLoader secondary )
+ {
+ ClassLoader[] primaryChain = getClassLoaderChain( primary );
+ ClassLoader[] secondaryChain = getClassLoaderChain( secondary );
+ return getCommonClassLoader( primaryChain, secondaryChain );
+ }
+
+ private static ClassLoader[] getClassLoaderChain( ClassLoader
classloader )
+ {
+ if( null == classloader )
+ {
+ return new ClassLoader[0];
+ }
+ else
+ {
+ ArrayList<ClassLoader> list = new ArrayList<ClassLoader>();
+ list.add( classloader );
+ ClassLoader parent = classloader.getParent();
+ while( null != parent )
+ {
+ list.add( parent );
+ parent = parent.getParent();
+ }
+ ArrayList<ClassLoader> result = new ArrayList<ClassLoader>();
+ int n = list.size() - 1;
+ for( int i=n; i>-1; i-- )
+ {
+ result.add( list.get( i ) );
+ }
+ return result.toArray( new ClassLoader[0] );
+ }
+ }
+
+ private static ClassLoader getCommonClassLoader( ClassLoader[] primary,
ClassLoader[] secondary )
+ {
+ ClassLoader anchor = null;
+ for( int i=0; i<primary.length; i++ )
+ {
+ ClassLoader classloader = primary[i];
+ if( secondary.length > i )
+ {
+ ClassLoader cl = secondary[i];
+ if( classloader == cl )
+ {
+ anchor = cl;
+ }
+ else
+ {
+ return anchor;
+ }
+ }
+ else
+ {
+ return anchor;
+ }
+ }
+ return anchor;
+ }
+
+ private static void list( StringBuffer buffer, ClassLoader classloader )
+ {
+ list( buffer, classloader, null );
+ }
+
+ private static void list( StringBuffer buffer, ClassLoader classloader,
ClassLoader anchor )
+ {
+ if( classloader == anchor )
+ {
+ return;
+ }
+ ClassLoader parent = classloader.getParent();
+ if( null != parent )
+ {
+ list( buffer, parent, anchor );
+ }
+ String label =
+ "\nClassLoader: "
+ + classloader.getClass().getName()
+ + " (" + System.identityHashCode( classloader ) + ")";
+ buffer.append( label );
+ if( classloader instanceof StandardClassLoader )
+ {
+ StandardClassLoader loader = (StandardClassLoader) classloader;
+ if( null != loader.m_name )
+ {
+ buffer.append( "\nLabel: " + loader.m_name + " " +
loader.m_category );
+ }
+ else
+ {
+ buffer.append( "\nCategory: " + loader.m_category );
+ }
+ }
+ if( classloader instanceof URLClassLoader )
+ {
+ URLClassLoader urlcl = (URLClassLoader) classloader;
+ buffer.append( "\n" );
+ appendEntries( buffer, urlcl );
+ }
+ }
+
+ /**
+ * Handle notification of the creation of a new classloader.
+ * @param logger the logging channel
+ * @param label the classloader label
+ * @param category the classloader category
+ * @param classloader the new classloader to report
+ */
+ private static void classloaderConstructed( Logger logger, String label,
Category category, ClassLoader classloader )
+ {
+ if( logger.isTraceEnabled() )
+ {
+ int id = System.identityHashCode( classloader );
+ StringBuffer buffer = new StringBuffer();
+ buffer.append( "new " );
+ buffer.append( category.toString() );
+ buffer.append( " classloader for " + label );
+ buffer.append( "\n id: " + id );
+ ClassLoader parent = classloader.getParent();
+ if( null != parent )
+ {
+ int pid = System.identityHashCode( parent );
+ buffer.append(
+ "\n extends: "
+ + pid );
+ }
+ if( classloader instanceof URLClassLoader )
+ {
+ URLClassLoader loader = (URLClassLoader) classloader;
+ URL[] urls = loader.getURLs();
+ if( urls.length == 1 )
+ {
+ buffer.append(
+ "\n contains: 1 entry" );
+ }
+ else
+ {
+ buffer.append(
+ "\n contains: "
+ + urls.length
+ + " entries" );
+ }
+ for( int i=0; i < urls.length; i++ )
+ {
+ URL url = urls[i];
+ buffer.append(
+ "\n ["
+ + ( i+1 )
+ + "] "
+ + url.toString() );
+ }
+ }
+ logger.trace( buffer.toString() );
+ }
+ }
+}

Copied: trunk/main/transit/core/src/main/dpml/util/StandardFormatter.java
(from rev 1789,
trunk/main/transit/core/src/main/net/dpml/util/StandardFormatter.java)
===================================================================
--- trunk/main/transit/core/src/main/net/dpml/util/StandardFormatter.java
2006-11-30 21:08:46 UTC (rev 1789)
+++ trunk/main/transit/core/src/main/dpml/util/StandardFormatter.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2005-2007 Stephen McConnell.
+ *
+ * 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 dpml.util;
+
+import java.util.logging.Formatter;
+import java.util.logging.LogRecord;
+
+/**
+ * Logging message formatter that includes the category in the logging
statement.
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class StandardFormatter extends Formatter
+{
+ private static final PID ID = new PID();
+
+ private static final String SEPARATOR = System.getProperty(
"line.separator" );
+
+ /**
+ * Format a LogRecord using a style appropriate for console messages. The
+ * the log record message will be checked for a process identifier that
is
+ * prepended to the raw message using the convention "$[" + PID + "] ".
If
+ * a process id is resolved the value is assigned to the process block
and
+ * the raw message is trimmed. The resulting formatted message is
presented
+ * in the form "[PID ] [LEVEL ] (log.category): the message".
+ *
+ * @param record the log record to be formatted.
+ * @return a formatted log record
+ */
+ public synchronized String format( LogRecord record )
+ {
+ if( null == record )
+ {
+ return "";
+ }
+ String process = getProcessHeader( record );
+ StringBuffer buffer = new StringBuffer( process );
+ String header = getLogHeader( record );
+ buffer.append( header );
+ if( null != record.getLoggerName() )
+ {
+ buffer.append( "(" + record.getLoggerName() + "): " );
+ }
+ else
+ {
+ buffer.append( "() " );
+ }
+ String message = getFormattedMessage( record );
+ buffer.append( message );
+ buffer.append( SEPARATOR );
+ if( record.getThrown() != null )
+ {
+ Throwable cause = record.getThrown();
+ boolean flag = getStackDumpRequired( cause );
+ String error = ExceptionHelper.packException( cause, flag );
+ buffer.append( error );
+ }
+ return buffer.toString();
+ }
+
+ private boolean getStackDumpRequired( Throwable cause )
+ {
+ if( cause instanceof Error )
+ {
+ return true;
+ }
+ else if( cause instanceof RuntimeException )
+ {
+ return true;
+ }
+ else
+ {
+ String value = System.getProperty( "dpml.debug", "false" );
+ if( "true".equals( value ) )
+ {
+ return true;
+ }
+ value = System.getProperty( "dpml.trace", "false" );
+ if( "true".equals( value ) )
+ {
+ return true;
+ }
+ return false;
+ }
+ }
+
+ private String getFormattedMessage( LogRecord record )
+ {
+ String message = formatMessage( record );
+ if( ( null != message ) && message.startsWith( "$[" ) )
+ {
+ int n = message.indexOf( "] " );
+ return message.substring( n + 2 );
+ }
+ else
+ {
+ return message;
+ }
+ }
+
+ private String getLogHeader( LogRecord record )
+ {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append( "[" );
+ buffer.append( record.getLevel().getLocalizedName() );
+ buffer.append( " " );
+ String tag = buffer.toString();
+ return tag.substring( 0, LEVEL_HEADER_WIDTH ) + "] ";
+ }
+
+ private String getProcessHeader( LogRecord record )
+ {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append( "[" );
+ String message = record.getMessage();
+ if( ( null != message ) && ( message.startsWith( "$[" ) ) )
+ {
+ int n = message.indexOf( "] " );
+ String id = message.substring( 2, n );
+ buffer.append( id );
+ }
+ else
+ {
+ buffer.append( ID.getValue() );
+ }
+ buffer.append( " " );
+ String tag = buffer.toString();
+ return tag.substring( 0, PROCESS_HEADER_WIDTH ) + "] ";
+ }
+
+ private static final int LEVEL_HEADER_WIDTH = 8;
+ private static final int PROCESS_HEADER_WIDTH = 6;
+}

Added: trunk/main/transit/core/src/main/dpml/util/SystemClassLoader.java
===================================================================
--- trunk/main/transit/core/src/main/dpml/util/SystemClassLoader.java
2007-02-08 23:39:34 UTC (rev 1832)
+++ trunk/main/transit/core/src/main/dpml/util/SystemClassLoader.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2005 Stephen J. McConnell.
+ *
+ * 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 dpml.util;
+
+import dpml.util.DefaultLogger;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URL;
+import java.util.List;
+import java.util.Arrays;
+
+import net.dpml.util.Logger;
+
+import net.dpml.transit.Transit;
+import net.dpml.transit.LinkManager;
+
+/**
+ * The SystemClassLoader is a URLClassLoader that supports late binding of
+ * URLs. This class may be configured as the system classloader when
loading plugins
+ * that declare system category plugin entries.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public final class SystemClassLoader extends StandardClassLoader
+{
+ private final ClassLoader m_parent;
+
+ private static final Logger LOGGER = new DefaultLogger( "dpml.lang" );
+
+ /**
+ * Creation of a new system classloader.
+ *
+ * @param parent the parent classloader
+ */
+ public SystemClassLoader( ClassLoader parent )
+ {
+ super( "system", Category.SYSTEM, new URL[0], parent );
+
+ m_parent = parent;
+
+ if( "true".equals( System.getProperty( "dpml.transit.include.tools"
) ) )
+ {
+ String jrePath = System.getProperty( "java.home" );
+ try
+ {
+ File jre = new File( jrePath );
+ File jdk = jre.getParentFile();
+ File lib = new File( jdk, "lib" );
+ File jar = new File( lib, "tools.jar" );
+ URI uri = jar.toURI();
+ URL url = uri.toURL();
+ addURL( url );
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "Internal error while attempting to establish tools.jar in
the system classloader.";
+ throw new Error( error, e );
+ }
+ }
+
+ String classpath = System.getProperty( "dpml.class.path" );
+ if( null != classpath )
+ {
+ try
+ {
+ String[] entries = classpath.split( ";" );
+ URI[] uris = new URI[ entries.length ];
+ for( int i=0; i<entries.length; i++ )
+ {
+ URI uri = URI.create( entries[i] );
+ if( "link".equals( uri.getScheme() ) )
+ {
+ uris[i] =
Transit.getInstance().getLinkManager().getTargetURI( uri );
+ }
+ else
+ {
+ uris[i] = uri;
+ }
+ }
+ addDelegates( uris );
+ }
+ catch( IOException e )
+ {
+ final String error =
+ "Internal error while installing system extensions.";
+ throw new Error( error, e );
+ }
+ }
+ }
+
+ private void addDelegates( final URI[] uris ) throws IOException
+ {
+ URL[] urls = toURLs( uris );
+ URL[] local = super.getURLs();
+ List list = Arrays.asList( local );
+ for( int i=0; i<urls.length; i++ )
+ {
+ URL url = urls[i];
+ if( !list.contains( url ) )
+ {
+ LOGGER.trace( "system extension: " + url );
+ addURL( url );
+ }
+ }
+ }
+}
+

Added: trunk/main/transit/core/src/main/dpml/util/package-info.java
===================================================================
--- trunk/main/transit/core/src/main/dpml/util/package-info.java
2007-02-08 23:39:34 UTC (rev 1832)
+++ trunk/main/transit/core/src/main/dpml/util/package-info.java
2007-02-08 23:42:59 UTC (rev 1833)
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2007 Stephen J. McConnell.
+ *
+ * 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.
+ */
+
+/**
+ * Internal utilities.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+package dpml.util;




  • r1833 - in trunk/main/transit/core/src/main/dpml: transit transit/artifact transit/info transit/link transit/local util, mcconnell at BerliOS, 02/08/2007

Archive powered by MHonArc 2.6.24.

Top of Page