Skip to Content.
Sympa Menu

notify-dpml - svn commit: r2459 - in development/main/transit: . core/handler/etc/setup/authority/hosts core/handler/src/main/net/dpml/transit core/handler/src/main/net/dpml/transit/cache core/handler/src/main/net/dpml/transit/event core/handler/src/main/net/dpml/transit/host core/handler/src/main/net/dpml/transit/images core/handler/src/main/net/dpml/transit/prefs core/handler/src/main/net/dpml/transit/util core/plugin/src/main/net/dpml/transit/control

notify-dpml AT lists.ibiblio.org

Subject: DPML Notify

List archive

Chronological Thread  
  • From: mcconnell AT dpml.net
  • To: notify-dpml AT lists.ibiblio.org
  • Subject: svn commit: r2459 - in development/main/transit: . core/handler/etc/setup/authority/hosts core/handler/src/main/net/dpml/transit core/handler/src/main/net/dpml/transit/cache core/handler/src/main/net/dpml/transit/event core/handler/src/main/net/dpml/transit/host core/handler/src/main/net/dpml/transit/images core/handler/src/main/net/dpml/transit/prefs core/handler/src/main/net/dpml/transit/util core/plugin/src/main/net/dpml/transit/control
  • Date: Wed, 04 May 2005 14:32:09 -0400

Author: mcconnell AT dpml.net
Date: Wed May 4 14:32:06 2005
New Revision: 2459

Added:
development/main/transit/core/handler/src/main/net/dpml/transit/event/

development/main/transit/core/handler/src/main/net/dpml/transit/event/EventProducer.java

development/main/transit/core/handler/src/main/net/dpml/transit/host/HostDescriptor.java

development/main/transit/core/handler/src/main/net/dpml/transit/host/HostDescriptorChangeEvent.java

development/main/transit/core/handler/src/main/net/dpml/transit/host/HostDescriptorChangeListener.java

development/main/transit/core/handler/src/main/net/dpml/transit/host/PreferencesResourceManager.java

development/main/transit/core/handler/src/main/net/dpml/transit/host/ResourceHostHelper.java
development/main/transit/core/handler/src/main/net/dpml/transit/images/

development/main/transit/core/handler/src/main/net/dpml/transit/images/cache.jpg
(contents, props changed)

development/main/transit/core/handler/src/main/net/dpml/transit/images/dpml.gif
(contents, props changed)

development/main/transit/core/handler/src/main/net/dpml/transit/images/http.png
(contents, props changed)

development/main/transit/core/handler/src/main/net/dpml/transit/images/item.gif
(contents, props changed)

development/main/transit/core/handler/src/main/net/dpml/transit/images/network.png
(contents, props changed)

development/main/transit/core/handler/src/main/net/dpml/transit/images/password.png
(contents, props changed)
development/main/transit/core/handler/src/main/net/dpml/transit/prefs/

development/main/transit/core/handler/src/main/net/dpml/transit/prefs/CachePanel.java

development/main/transit/core/handler/src/main/net/dpml/transit/prefs/DefaultCellRenderer.java

development/main/transit/core/handler/src/main/net/dpml/transit/prefs/HostPanel.java

development/main/transit/core/handler/src/main/net/dpml/transit/prefs/HostsTable.java

development/main/transit/core/handler/src/main/net/dpml/transit/prefs/HostsTableModel.java

development/main/transit/core/handler/src/main/net/dpml/transit/prefs/IconHelper.java

development/main/transit/core/handler/src/main/net/dpml/transit/prefs/ResourcePanel.java

development/main/transit/core/handler/src/main/net/dpml/transit/prefs/TransitDialog.java

development/main/transit/core/handler/src/main/net/dpml/transit/prefs/package.html
Modified:
development/main/transit/core/handler/etc/setup/authority/hosts/local.host

development/main/transit/core/handler/etc/setup/authority/hosts/repository.dpml.net.host
development/main/transit/core/handler/src/main/net/dpml/transit/Main.java

development/main/transit/core/handler/src/main/net/dpml/transit/SecuredTransitContext.java

development/main/transit/core/handler/src/main/net/dpml/transit/cache/CacheHandler.java

development/main/transit/core/handler/src/main/net/dpml/transit/cache/FileCacheHandler.java

development/main/transit/core/handler/src/main/net/dpml/transit/host/ClassicResourceHost.java

development/main/transit/core/handler/src/main/net/dpml/transit/host/ResourceHost.java

development/main/transit/core/handler/src/main/net/dpml/transit/host/ResourceHostFactory.java

development/main/transit/core/handler/src/main/net/dpml/transit/host/ResourceManager.java

development/main/transit/core/handler/src/main/net/dpml/transit/host/StandardResourceManager.java

development/main/transit/core/handler/src/main/net/dpml/transit/util/Util.java

development/main/transit/core/plugin/src/main/net/dpml/transit/control/CommandHandler.java

development/main/transit/core/plugin/src/main/net/dpml/transit/control/Resources.properties
development/main/transit/standard.xml
Log:
Addition of support for preferences based configuration. This commit
includes updates to Main that recognize a -prefs commandline option. If
selected then prefs based configuration will kick in. The implementation is
primarily a vaidation exercise and will require further work if we decide to
move ahead with this strategy. The further work is basically related to (a)
eliminating multiple configuration mechanissms, and (b) probably adding a
hosts registry that will simplfy the implementation of a cache handler (but
more on this on the list). Another feature of the commit is an interactive
prefs editor that is launched using the -manager command line option. An
-Xreset command line option will revert all preference setting to factory
defaults.

Modified:
development/main/transit/core/handler/etc/setup/authority/hosts/local.host
==============================================================================
---
development/main/transit/core/handler/etc/setup/authority/hosts/local.host
(original)
+++
development/main/transit/core/handler/etc/setup/authority/hosts/local.host
Wed May 4 14:32:06 2005
@@ -1,10 +1,7 @@
dpml.transit.resourcehost.enabled=true
dpml.transit.resourcehost.class=net.dpml.transit.host.ClassicResourceHost
dpml.transit.resourcehost.base=file:${dpml.system}/local
-dpml.transit.resourcehost.knowngroups=
dpml.transit.resourcehost.priority=10
dpml.transit.resourcehost.trusted=true
dpml.transit.resourcehost.policy=timestamp
-dpml.transit.resourcehost.username=
-dpml.transit.resourcehost.password=


Modified:
development/main/transit/core/handler/etc/setup/authority/hosts/repository.dpml.net.host
==============================================================================
---
development/main/transit/core/handler/etc/setup/authority/hosts/repository.dpml.net.host
(original)
+++
development/main/transit/core/handler/etc/setup/authority/hosts/repository.dpml.net.host
Wed May 4 14:32:06 2005
@@ -1,10 +1,10 @@
dpml.transit.resourcehost.enabled=true
dpml.transit.resourcehost.class=net.dpml.transit.host.ClassicResourceHost
dpml.transit.resourcehost.base=http://repository.dpml.net/classic
-dpml.transit.resourcehost.knowngroups=
dpml.transit.resourcehost.priority=40
dpml.transit.resourcehost.trusted=false
dpml.transit.resourcehost.policy=fast
-dpml.transit.resourcehost.username=
-dpml.transit.resourcehost.password=
+#dpml.transit.resourcehost.knowngroups=
+#dpml.transit.resourcehost.username=
+#dpml.transit.resourcehost.password=


Modified:
development/main/transit/core/handler/src/main/net/dpml/transit/Main.java
==============================================================================
--- development/main/transit/core/handler/src/main/net/dpml/transit/Main.java
(original)
+++ development/main/transit/core/handler/src/main/net/dpml/transit/Main.java
Wed May 4 14:32:06 2005
@@ -31,6 +31,7 @@
import net.dpml.transit.monitors.RepositoryMonitor;
import net.dpml.transit.monitors.SystemMonitor;
import net.dpml.transit.util.Dictionary;
+import net.dpml.transit.prefs.TransitDialog;

import java.io.File;
import java.io.FileInputStream;
@@ -38,6 +39,7 @@
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Map;
+import java.util.prefs.Preferences;

/**
* CLI hander for the transit package.
@@ -128,6 +130,49 @@
SystemMonitor monitor = new SystemMonitor( console );

//
+ // check if a prefs reset has been requested
+ //
+
+ for( int i=0; i < args.length; i++ )
+ {
+ String arg = args[i];
+ if( arg.equals( "-Xreset" ) )
+ {
+ try
+ {
+ Preferences usr = Preferences.userNodeForPackage(
Transit.class );
+ System.out.println( "resetting preferences: " + usr );
+ usr.removeNode();
+ usr.flush();
+ Preferences sys = Preferences.systemNodeForPackage(
Transit.class );
+ System.out.println( "resetting preferences: " + sys );
+ sys.removeNode();
+ sys.flush();
+ }
+ catch( Throwable e )
+ {
+ System.out.println( "RESET ERROR" );
+ e.printStackTrace();
+ }
+ }
+ }
+
+ //
+ // check if a prefs are enabled (default is false)
+ //
+
+ boolean interactive = args.length == 0; // doubleclick on jar file
+
+ for( int i=0; i < args.length; i++ )
+ {
+ String arg = args[i];
+ if( arg.equals( "-prefs" ) || arg.equals( "-manager" ) ||
interactive )
+ {
+ System.setProperty( "dpml.transit.preferences.enabled",
"true" );
+ }
+ }
+
+ //
// setup transit
//

@@ -188,7 +233,7 @@
path = BOOTSTRAP_URI;
}

- String[] arguments = collapseArgs( args );
+ String[] arguments = collapseArgs( interactive, args );
URI uri = Artifact.createArtifact( path ).toURI();

Map data = new Hashtable();
@@ -214,21 +259,21 @@
* @param args the commandline args
* @return the applications arugments
*/
- private static String[] collapseArgs( String[] args )
+ private static String[] collapseArgs( boolean interactive, String[] args
)
{
+ if( interactive )
+ {
+ return new String[]{ "-manager" };
+ }
ArrayList list = new ArrayList();
for( int i=0; i < args.length; i++ )
{
String arg = args[i];
- if( "-Xdebug".equals( arg ) )
- {
- continue;
- }
- if( arg.startsWith( "-Xbootstrap=" ) )
- {
- continue;
- }
- if( arg.startsWith( "-Xmanager=" ) )
+ if( "-Xdebug".equals( arg )
+ || arg.startsWith( "-Xbootstrap=" )
+ || arg.startsWith( "-Xreset" )
+ || arg.startsWith( "-prefs" )
+ )
{
continue;
}

Modified:
development/main/transit/core/handler/src/main/net/dpml/transit/SecuredTransitContext.java
==============================================================================
---
development/main/transit/core/handler/src/main/net/dpml/transit/SecuredTransitContext.java
(original)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/SecuredTransitContext.java
Wed May 4 14:32:06 2005
@@ -39,6 +39,7 @@
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
+import java.util.prefs.Preferences;
import java.util.Properties;

/**
@@ -114,6 +115,11 @@
static public final String TRANSIT_PROPERTIES_FILENAME =
"transit.properties";

/**
+ * The proxy prompt/realm key.
+ */
+ static public final String PREFERENCES_ENABLED_KEY = DOMAIN +
".preferences.enabled";
+
+ /**
* The singleton transit context.
*/
private static SecuredTransitContext m_CONTEXT;
@@ -209,7 +215,16 @@
URL authorative = establishAuthority( monitor );
monitor.notifyAuthority( authorative );
Properties props = getTransitProperties( authorative );
- String classname = getResourceManagerClassname( props );
+ String classname = null;
+ boolean flag = isPreferencesEnabled( props );
+ if( flag )
+ {
+ classname = getResourceManagerClassname(); // using
preferences
+ }
+ else
+ {
+ classname = getResourceManagerClassname( props ); //
using properties
+ }
ResourceManager manager = createResourceManager( classname,
authorative, monitor );
CacheHandler ch = manager.createCacheHandler();
monitor.notifyCacheHandlerCreation( ch );
@@ -264,6 +279,39 @@
}

/**
+ * Return TRUE if preference managment is enabled.
+ *
+ * @param props the transit properties
+ * @return the preferences enabled status
+ */
+ private static boolean isPreferencesEnabled( Properties props )
+ {
+ String value = System.getProperty(
+ PREFERENCES_ENABLED_KEY,
+ props.getProperty( PREFERENCES_ENABLED_KEY, "false" ) );
+ return "true".equals( value );
+ }
+
+ /**
+ * Return the classname of the class implementating the resource manager.
+ * Resolved relative to the system property
'dpml.transit.authority.resourcemanager.classname'.
+ * with fallback to preferencees defained under the Transit class package
group.
+ * If undefined the default classname is returned.
+ *
+ * @return the resource manager classname
+ */
+ private static String getResourceManagerClassname()
+ {
+ final String key = "resource-manager-classname";
+ final String fallback =
ResourceManager.TRANSIT_PREFS_RESOURCE_MANAGER_CLASSNAME;
+ Preferences systemPrefs = Preferences.systemNodeForPackage(
Transit.class );
+ Preferences userPrefs = Preferences.userNodeForPackage(
Transit.class );
+ return System.getProperty(
+ ResourceManager.TRANSIT_RESOURCE_MANAGER_CLASSNAME_KEY,
+ userPrefs.get( key, systemPrefs.get( key, fallback ) ) );
+ }
+
+ /**
* Return the classname of the class implementating the resource manager.
* Resolved relative to the transit property
'dpml.transit.authority.resourcemanager.classname'.
* If undefined the default classname is returned.
@@ -275,9 +323,9 @@
{
return System.getProperty(
ResourceManager.TRANSIT_RESOURCE_MANAGER_CLASSNAME_KEY,
- props.getProperty(
- ResourceManager.TRANSIT_RESOURCE_MANAGER_CLASSNAME_KEY,
- ResourceManager.TRANSIT_RESOURCE_MANAGER_CLASSNAME ) );
+ props.getProperty(
+ ResourceManager.TRANSIT_RESOURCE_MANAGER_CLASSNAME_KEY,
+ ResourceManager.TRANSIT_RESOURCE_MANAGER_CLASSNAME ) );
}

/**

Modified:
development/main/transit/core/handler/src/main/net/dpml/transit/cache/CacheHandler.java
==============================================================================
---
development/main/transit/core/handler/src/main/net/dpml/transit/cache/CacheHandler.java
(original)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/cache/CacheHandler.java
Wed May 4 14:32:06 2005
@@ -31,8 +31,8 @@

/**
* The CacheHandler interface defines the contract for classes capable of
- * supporting the cache mentement aspects of a transit system. Cache
management
- * encompasses the retreval of resources based on artifact identifiers.
Cache
+ * supporting the cache management aspects of a transit system. Cache
management
+ * encompasses the retreval of resources based on artifact identifiers. A
cache
* manager implementations may provide varying levels of quality-of-services.
* Selection of a cache manager is defined under the transit cache
configuration
* properties.

Modified:
development/main/transit/core/handler/src/main/net/dpml/transit/cache/FileCacheHandler.java
==============================================================================
---
development/main/transit/core/handler/src/main/net/dpml/transit/cache/FileCacheHandler.java
(original)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/cache/FileCacheHandler.java
Wed May 4 14:32:06 2005
@@ -19,18 +19,6 @@

package net.dpml.transit.cache;

-import net.dpml.lang.NullArgumentException;
-import net.dpml.transit.Transit;
-import net.dpml.transit.TransitException;
-import net.dpml.transit.artifact.Artifact;
-import net.dpml.transit.artifact.ArtifactAlreadyExistsException;
-import net.dpml.transit.artifact.ArtifactNotFoundException;
-import net.dpml.transit.host.ResourceHost;
-import net.dpml.transit.layout.LocationResolver;
-import net.dpml.transit.monitors.CacheMonitorRouter;
-import net.dpml.transit.monitors.Monitor;
-import net.dpml.transit.util.Util;
-
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
@@ -42,14 +30,39 @@
import java.util.Iterator;
import java.util.Properties;
import java.util.TreeMap;
+import java.util.prefs.Preferences;
+import java.util.prefs.PreferenceChangeListener;
+import java.util.prefs.PreferenceChangeEvent;
+import java.util.prefs.BackingStoreException;
+import java.util.prefs.NodeChangeListener;
+import java.util.prefs.NodeChangeEvent;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

+import net.dpml.lang.NullArgumentException;
+import net.dpml.transit.Transit;
+import net.dpml.transit.TransitException;
+import net.dpml.transit.artifact.Artifact;
+import net.dpml.transit.artifact.ArtifactAlreadyExistsException;
+import net.dpml.transit.artifact.ArtifactNotFoundException;
+import net.dpml.transit.host.ResourceHost;
+import net.dpml.transit.host.ResourceHostHelper;
+import net.dpml.transit.host.HostDescriptor;
+import net.dpml.transit.host.HostDescriptorChangeEvent;
+import net.dpml.transit.host.HostDescriptorChangeListener;
+import net.dpml.transit.layout.LocationResolver;
+import net.dpml.transit.monitors.CacheMonitorRouter;
+import net.dpml.transit.monitors.Monitor;
+import net.dpml.transit.util.Util;
+
/**
- * Default cache handler that maintains a file based cache.
+ * Default cache handler that maintains a file based cache. The handler
registers a
+ * listener on the CacheHandler preferences node to listen for changes
related to
+ * cache configuration, and another listener for changes to subsidiary node
changes
+ * reflecting the addition, modification and removal of hosts.
*/
public class FileCacheHandler
- implements CacheHandler
+ implements CacheHandler, PreferenceChangeListener, NodeChangeListener,
HostDescriptorChangeListener
{
//
------------------------------------------------------------------------
// state
@@ -69,18 +82,73 @@

private ZipCache m_zipCache;

+ private Monitor m_monitor;
+
+ private boolean m_flag = false;
+
//
------------------------------------------------------------------------
- // constructor
+ // constructor (preferences based)
//
------------------------------------------------------------------------

/**
- * Creation of a new file based cache handler.
+ * Creation of a new file based cache handler using system preferences.
+ * @param monitor the assigned monitor
+ * @param resolver the location resolver
+ */
+ public FileCacheHandler( Monitor monitor, LocationResolver resolver )
throws TransitException
+ {
+ m_monitor = monitor;
+ m_zipCache = new ZipCache();
+ m_resourceHosts = new TreeMap();
+ m_resolver = resolver;
+ m_flag = true;
+
+ //
+ // construct the hosts using the system preferences
+ //
+
+ Preferences prefs = Preferences.userNodeForPackage(
ResourceHost.class );
+ try
+ {
+ String[] names = getHostNodeNames();
+ for( int i=0; i<names.length; i++ )
+ {
+ String name = names[i];
+ Preferences p = prefs.node( name );
+ handleHostAddition( p );
+ }
+ }
+ catch( Exception e )
+ {
+ final String error =
+ "Unexpected exception while reading host preferences."
+ + "\nPreferences: " + prefs;
+ throw new TransitException( error, e );
+ }
+
+ //
+ // add a listener to the user preferences
+ //
+
+ prefs.addPreferenceChangeListener( this );
+ prefs.addNodeChangeListener( this );
+ File cache = resolveCacheDirectory();
+ setLocalCacheDirectory( cache );
+ }
+
+ //
------------------------------------------------------------------------
+ // constructor (properties based)
+ //
------------------------------------------------------------------------
+
+ /**
+ * Creation of a new file based cache handler using supplied hosts and
properties.
* @param monitor the assigned monitor
* @param hosts the assigned hosts
* @param props the properties against which this instance will be
configured
*/
public FileCacheHandler( Monitor monitor, ResourceHost[] hosts,
Properties props, LocationResolver resolver )
{
+ m_monitor = monitor;
m_zipCache = new ZipCache();

m_resolver = resolver;
@@ -104,20 +172,45 @@
}
m_resourceHosts.put( key, hosts[i] );
}
- m_cacheDir = createCacheDirectory( props );
+
+ File cache = resolveCacheDirectory( props );
+ setLocalCacheDirectory( cache );
monitor.trace( "created file based cache on: " + m_cacheDir );
+
}

/**
* Set the local cache directory.
*
*/
- protected void setLocalCacheDirectory( File file )
+ protected synchronized void setLocalCacheDirectory( File file )
{
- synchronized( m_cacheDir )
+ if( null == file )
+ {
+ throw new NullArgumentException( "file" );
+ }
+ File cache = file;
+ if( null == m_cacheDir )
+ {
+ final String message =
+ "Setting cache directory."
+ + "\nDirectory: " + cache;
+ m_monitor.trace( message );
+ }
+ else
+ {
+ final String message =
+ "Changing cache directory."
+ + "\nOld: " + m_cacheDir
+ + "\nNew: " + cache;
+ m_monitor.trace( message );
+ }
+ if( false == cache.isAbsolute() )
{
- m_cacheDir = file;
+ cache = new File( Transit.DPML_DATA, file.toString() );
}
+ cache.mkdirs();
+ m_cacheDir = cache;
}

/**
@@ -326,23 +419,36 @@
/**
* Create the file to the root of the cache directory. If the cache key is
* declared as a system property, the value will take precidence over the
- * cache configuration properties.
+ * cache configuration properties. If the cache key is declared as a
system
+ * property, the system prioperty value will take precidence over the
+ * cache preferences.
*
* @param props the configuration properties
* @return the cache root directory
*/
- private File createCacheDirectory( Properties props )
+ private File resolveCacheDirectory( Properties props )
{
String defaultCache = "cache";
String fallback = Util.getProperty( props, CACHE_KEY, defaultCache );
String cache = System.getProperty( CACHE_KEY, fallback );
- File cachedir = new File( cache );
- if( !cachedir.isAbsolute() )
- {
- cachedir = new File( Transit.DPML_DATA, cache );
- }
- cachedir.mkdirs();
- return cachedir;
+ return new File( cache );
+ }
+
+ /**
+ * Resolve the cache directory using the preferences assigned under the
+ * net.dpml.transit.cache package group using the "location" key.
+ *
+ * @return the cache directory
+ */
+ private File resolveCacheDirectory()
+ {
+ String defaultCache = "cache";
+ Preferences system = Preferences.systemNodeForPackage(
FileCacheHandler.class );
+ String systemPreference = system.get( "location", defaultCache );
+ Preferences user = Preferences.userNodeForPackage(
FileCacheHandler.class );
+ String userPreference = user.get( "location", systemPreference );
+ String cache = System.getProperty( CACHE_KEY, userPreference );
+ return new File( cache );
}

private void endNotifyMonitor( CacheMonitorRouter monitor, boolean
existed,
@@ -422,4 +528,112 @@
return destination;
}

+ //
------------------------------------------------------------------------
+ // PreferencesChangeListener (listens to cache prefs)
+ //
------------------------------------------------------------------------
+
+ public void preferenceChange( PreferenceChangeEvent event )
+ {
+ String key = event.getKey();
+ String value = event.getNewValue();
+ if( "location".equals( key ) )
+ {
+ File cache = resolveCacheDirectory();
+ setLocalCacheDirectory( cache );
+ }
+ }
+
+ //
------------------------------------------------------------------------
+ // NodeChangeListener (listens to host prefs addition and removal)
+ //
------------------------------------------------------------------------
+
+ /**
+ * Handle the addition of a host following a preferences node change.
+ *
+ * @param event the node addition event
+ */
+ public void childAdded( NodeChangeEvent event )
+ {
+ Preferences prefs = event.getChild();
+ handleHostAddition( prefs );
+ }
+
+ public void childRemoved( NodeChangeEvent event )
+ {
+ Preferences prefs = event.getChild();
+ String name = prefs.name();
+ m_resourceHosts.remove( name );
+ }
+
+ //
------------------------------------------------------------------------
+ // HostChangedListener (listens to changes in a host descriptor)
+ //
------------------------------------------------------------------------
+
+ // TODO: update all of this once we switch to prefs - we should be
creating
+ // a ResourceHost without any concern for exceptions and leave it up to
the
+ // ResourceHost implementation to maintain its own availability based on
the
+ // underlying prefs and it's own state - so for example, if it has a bad
base
+ // url it would automatically declare itself as unavailable and expose
+ // somewhere the reason for non-availability
+
+ public void hostChanged( HostDescriptorChangeEvent event )
+ {
+ HostDescriptor descriptor = event.getDescriptor();
+ String name = descriptor.getHostName();
+ if( false == m_resourceHosts.containsKey( name ) )
+ {
+ if( descriptor.getLastModified() > 0 )
+ {
+ descriptor.removeHostDescriptorChangeListener( this );
+ ResourceHost host = createResourceHost( descriptor );
+ m_resourceHosts.put( name, host );
+ }
+ }
+ }
+
+ //
------------------------------------------------------------------------
+ // prefs utilities
+ //
------------------------------------------------------------------------
+
+ private Preferences getUserHostNode()
+ {
+ return Preferences.userNodeForPackage( ResourceHost.class );
+ }
+
+ private String[] getHostNodeNames() throws BackingStoreException
+ {
+ return getUserHostNode().childrenNames();
+ }
+
+ private void handleHostAddition( Preferences prefs )
+ {
+ HostDescriptor descriptor = new HostDescriptor( prefs );
+ if( descriptor.getLastModified() > 0 )
+ {
+ String name = descriptor.getHostName();
+ ResourceHost host = createResourceHost( descriptor );
+ m_resourceHosts.put( name, host );
+ }
+ else
+ {
+ descriptor.addHostDescriptorChangeListener( this );
+ }
+ }
+
+ private ResourceHost createResourceHost( HostDescriptor descriptor )
+ {
+ try
+ {
+ return ResourceHostHelper.createResourceHost( descriptor );
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "Unexpected error while attempting to add a resource host."
+ + "\nHost: " + descriptor;
+ RuntimeException exception = new RuntimeException( error );
+ exception.initCause( e );
+ throw exception;
+ }
+ }
}

Added:
development/main/transit/core/handler/src/main/net/dpml/transit/event/EventProducer.java
==============================================================================
--- (empty file)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/event/EventProducer.java
Wed May 4 14:32:06 2005
@@ -0,0 +1,240 @@
+/*
+ * 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.event;
+
+import java.util.EventObject;
+import java.util.EventListener;
+import java.util.List;
+import java.util.LinkedList;
+
+import net.dpml.transit.adapter.ExceptionHelper;
+
+
+/**
+ * A abstract base class that established an event queue and handles event
dispatch
+ * operations for listeners declared in a class extending this base class.
+ */
+public abstract class EventProducer
+{
+ /**
+ * Registered event listeners.
+ */
+ private EventListener[] m_listeners = new EventListener[0];
+
+ /**
+ * Internal synchronization lock.
+ */
+ protected final Object m_lock = new Object();
+
+ /**
+ * Abstract operation to be implemented by classes extending this base
class.
+ * An implementation is reposible for the posting of the event to
associated
+ * listeners. Event posting will be executed under a separate thread to
the
+ * thread that initiated the event post.
+ *
+ * @param event the event to process
+ */
+ protected abstract void processEvent( EventObject event );
+
+ /**
+ * Add a listener to the set of listeners handled by this producer.
+ * @param listener the event listener
+ */
+ protected void addListener( EventListener listener )
+ {
+ if( null == listener )
+ {
+ throw new NullPointerException( "listener" );
+ }
+
+ synchronized( m_lock )
+ {
+ Object[] old = m_listeners;
+ m_listeners = new EventListener[ old.length + 1 ];
+ System.arraycopy( old, 0, m_listeners, 0, old.length );
+ m_listeners[old.length] = listener;
+ }
+ startEventDispatchThread();
+ }
+
+ /**
+ * Remove a listener to the set of listeners handled by this producer.
+ * @param listener the event listener
+ */
+ protected void removeListener( EventListener listener )
+ {
+ if( null == listener )
+ {
+ throw new NullPointerException( "listener" );
+ }
+
+ synchronized( m_lock )
+ {
+ if( m_listeners.length == 0 )
+ {
+ throw new IllegalArgumentException( "Listener not
registered." );
+ }
+ // create the copy
+ EventListener[] replacement = new EventListener[
m_listeners.length - 1 ];
+ // copy listeners from 0 up to the listener being removed
+ int i=0;
+ while( i < replacement.length && m_listeners[i] != listener )
+ {
+ replacement[i] = m_listeners[i++];
+ }
+ // check that the listener has been located
+ if( i == replacement.length && m_listeners[i] != listener )
+ {
+ throw new IllegalArgumentException( "Listener not
registered." );
+ }
+ // complete the copy operation
+ while( i < replacement.length )
+ {
+ replacement[i] = m_listeners[++i];
+ }
+ // commit the copy
+ m_listeners = replacement;
+ }
+ }
+
+ /**
+ * Queue of pending notification events. When an event for which
+ * there are one or more listeners occurs, it is placed on this queue
+ * and the queue is notified. A background thread waits on this queue
+ * and delivers the events. This decouples event delivery from
+ * the application concern, greatly simplifying locking and reducing
+ * opportunity for deadlock.
+ */
+ private static final List EVENT_QUEUE = new LinkedList();
+
+ /**
+ * A single background thread ("the event notification thread") monitors
+ * the event queue and delivers events that are placed on the queue.
+ */
+ private static class EventDispatchThread extends Thread
+ {
+ public void run()
+ {
+ while( true )
+ {
+ // Wait on EVENT_QUEUE till an event is present
+ EventObject event = null;
+ synchronized( EVENT_QUEUE )
+ {
+ try
+ {
+ while( EVENT_QUEUE.isEmpty() )
+ {
+ EVENT_QUEUE.wait();
+ }
+ Object object = EVENT_QUEUE.remove(0);
+ try
+ {
+ event = (EventObject) object;
+ }
+ catch( ClassCastException cce )
+ {
+ final String error =
+ "Unexpected class cast exception while
processing an event."
+ + "\nEvent: " + object;
+ throw new IllegalStateException( error );
+ }
+ }
+ catch (InterruptedException e)
+ {
+ return;
+ }
+ }
+
+ Object source = event.getSource();
+ if( source instanceof EventProducer )
+ {
+ EventProducer producer = (EventProducer) source;
+ try
+ {
+ producer.processEvent( event );
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "Unexpected error while processing event."
+ + "\nEvent: " + event
+ + "\nSource: " + source;
+ String msg = ExceptionHelper.packException( error,
e, true );
+ System.err.println( msg );
+ }
+ }
+ else
+ {
+ final String error =
+ "Event source is not an instance of " +
EventProducer.class.getName();
+ throw new IllegalStateException( error );
+ }
+ }
+ }
+ }
+
+ private static Thread EVENT_DISPATCH_THREAD = null;
+
+ /**
+ * This method starts the event dispatch thread the first time it
+ * is called. The event dispatch thread will be started only
+ * if someone registers a listener.
+ */
+ private static synchronized void startEventDispatchThread()
+ {
+ if( EVENT_DISPATCH_THREAD == null )
+ {
+ EVENT_DISPATCH_THREAD = new EventDispatchThread();
+ EVENT_DISPATCH_THREAD.setDaemon( true );
+ EVENT_DISPATCH_THREAD.start();
+ }
+ }
+
+ /**
+ * Return this node's preference/node change listeners. Even though
+ * we're using a copy-on-write lists, we use synchronized accessors to
+ * ensure information transmission from the writing thread to the
+ * reading thread.
+ */
+ protected EventListener[] listeners()
+ {
+ synchronized( m_lock )
+ {
+ return m_listeners;
+ }
+ }
+
+ /**
+ * Enqueue an event for delivery to registered
+ * listeners unless there are no registered
+ * listeners.
+ */
+ protected void enqueueEvent( EventObject event )
+ {
+ if( m_listeners.length != 0 )
+ {
+ synchronized( EVENT_QUEUE )
+ {
+ EVENT_QUEUE.add( event );
+ EVENT_QUEUE.notify();
+ }
+ }
+ }
+}

Modified:
development/main/transit/core/handler/src/main/net/dpml/transit/host/ClassicResourceHost.java
==============================================================================
---
development/main/transit/core/handler/src/main/net/dpml/transit/host/ClassicResourceHost.java
(original)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/host/ClassicResourceHost.java
Wed May 4 14:32:06 2005
@@ -19,20 +19,6 @@

package net.dpml.transit.host;

-import net.dpml.transit.Transit;
-
-import net.dpml.transit.artifact.Artifact;
-
-import net.dpml.transit.layout.ClassicResolver;
-import net.dpml.transit.layout.LocationResolver;
-
-import net.dpml.transit.network.ConnectionCache;
-import net.dpml.transit.network.DelegatingAuthenticator;
-import net.dpml.transit.network.NetworkLoader;
-import net.dpml.transit.network.RequestIdentifier;
-import net.dpml.transit.network.TransitAuthenticator;
-import net.dpml.transit.network.TransitAuthenticatorImpl;
-
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
@@ -61,6 +47,24 @@
import java.util.HashMap;
import java.util.HashSet;

+import java.util.prefs.Preferences;
+import java.util.prefs.PreferenceChangeListener;
+import java.util.prefs.PreferenceChangeEvent;
+
+import net.dpml.transit.Transit;
+import net.dpml.transit.TransitException;
+
+import net.dpml.transit.artifact.Artifact;
+
+import net.dpml.transit.layout.ClassicResolver;
+import net.dpml.transit.layout.LocationResolver;
+
+import net.dpml.transit.network.ConnectionCache;
+import net.dpml.transit.network.DelegatingAuthenticator;
+import net.dpml.transit.network.NetworkLoader;
+import net.dpml.transit.network.RequestIdentifier;
+import net.dpml.transit.network.TransitAuthenticator;
+import net.dpml.transit.network.TransitAuthenticatorImpl;

/** This class represents a single host where resources are stored at.
* <p>
@@ -69,7 +73,7 @@
* </p>
*/
public class ClassicResourceHost
- implements ResourceHost
+ implements ResourceHost, HostDescriptorChangeListener
{
//
------------------------------------------------------------------------
// static
@@ -102,14 +106,14 @@
/**
* Known groups.
*/
- private HashSet m_knownGroups;
+ private HashSet m_knownGroups = new HashSet();

/**
* locks.
* The key is the Artifact one wants to lock against, and the value is an
* anonymously lock object.
*/
- private HashMap m_locks;
+ private HashMap m_locks = new HashMap();

/**
* Host priority.
@@ -134,7 +138,58 @@
private LocationResolver m_resolver;

//
------------------------------------------------------------------------
- // constructor
+ // constructor (preference based)
+ //
------------------------------------------------------------------------
+
+ /**
+ * Constructor for a resource host using a supplied Perferences
instance. The
+ * implementation registeres itdself as a preferences change listener
and maintains
+ * the synchronization of this instance with the supplied preferences
instance.
+ *
+ * @param prefs the host preferences object
+ * @exception UnknownHostException if the supplied base url references
an unknown host
+ */
+ public ClassicResourceHost( HostDescriptor descriptor )
+ throws UnknownHostException, TransitException, UnknownHostException,
IOException
+ {
+ descriptor.addHostDescriptorChangeListener( this );
+ if( descriptor.getLastModified() > 0 )
+ {
+ m_enabled = descriptor.getEnabled();
+ }
+ else
+ {
+ m_enabled = false;
+ }
+ m_connections = ConnectionCache.getInstance();
+ m_resolver = setupResolver( descriptor );
+ m_priority = descriptor.getPriority();
+ m_trusted = descriptor.getTrusted();
+ m_baseUrl = setupBase( descriptor );
+ String[] groups = setupGroups( descriptor );
+ resetGroups( groups );
+ setupAuthenticator( m_baseUrl, descriptor );
+
+ // TODO: add a node change listener on the parent node so we can
+ // destroy ourselves and release the listener if the node is dropped
+
+ }
+
+ private void resetGroups( String[] groups )
+ {
+ synchronized( m_knownGroups )
+ {
+ m_knownGroups.clear();
+ for( int i = 0; i < groups.length; i++ )
+ {
+ String group = groups[i];
+ m_knownGroups.add( group );
+ }
+ }
+ }
+
+ //
------------------------------------------------------------------------
+ // constructor (long list of parameters based)
//
------------------------------------------------------------------------

/** Constructor for a resource host.
@@ -164,11 +219,9 @@
m_resolver = resolver;
else
m_resolver = new ClassicResolver();
- m_locks = new HashMap();
m_connections = ConnectionCache.getInstance();
m_baseUrl = base;
m_priority = priority;
- m_knownGroups = new HashSet();
m_trusted = trusted;
m_enabled = enabled;

@@ -203,6 +256,122 @@
}

//
------------------------------------------------------------------------
+ // PreferenceChangeListener
+ //
------------------------------------------------------------------------
+
+ // ### This should be dumped as soon as we decide to switch over to
prefs based
+ // ### management. We should be reading directory of the HostDescriptor
instead of
+ // ### holding state locally.
+
+ public void hostChanged( HostDescriptorChangeEvent event )
+ {
+ HostDescriptor descriptor = event.getDescriptor();
+ if( descriptor.getLastModified() > 0 )
+ {
+ m_enabled = descriptor.getEnabled();
+ }
+ else
+ {
+ m_enabled = false;
+ }
+ if( m_trusted != descriptor.getTrusted() )
+ {
+ m_trusted = descriptor.getTrusted();
+ }
+ if( false == m_baseUrl.toExternalForm().equals(
descriptor.getBasePath() ) )
+ {
+ synchronized( this )
+ {
+ try
+ {
+ m_baseUrl = setupBase( descriptor );
+ setupAuthenticator( m_baseUrl, descriptor );
+ String[] groups = setupGroups( descriptor );
+ resetGroups( groups );
+ }
+ catch( Exception e )
+ {
+ // TODO: interesting scenario ..
+ // the preferences are already updated - in principal
+ // we should disable or reset the host and issue a
high-level transit event
+ // that can be captured by a management system, but
beyond this, we should
+ // probably reach down and flag the preferences as
invalid
+
+ m_enabled = false;
+
+ System.out.println( "# ERROR IN HOST CHANGE" );
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ private LocationResolver setupResolver( HostDescriptor descriptor )
throws TransitException
+ {
+ String resolverClassname = descriptor.getResolverClassname();
+ return ResourceHostHelper.createResolver( resolverClassname );
+ }
+
+ private URL setupBase( HostDescriptor descriptor ) throws
UnknownHostException, IOException
+ {
+ String baseSpec = descriptor.getBasePath();
+ if( null == baseSpec )
+ {
+ final String error =
+ "Undefined base url.";
+ throw new UnknownHostException( error );
+ }
+ return new URL( baseSpec );
+ }
+
+ private String[] setupGroups( HostDescriptor descriptor ) throws
IOException
+ {
+ String indexSpec = descriptor.getIndexPath();
+ if( null != indexSpec )
+ {
+ // TODO: fix this so that the url is resolved relative to the
base
+ URL index = new URL( indexSpec );
+ return ResourceHostHelper.getKnownGroups( index );
+ }
+ else
+ {
+ return new String[0];
+ }
+ }
+
+ private void setupAuthenticator( URL base, HostDescriptor descriptor )
+ {
+ 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;
+ }
+ }
+
+ String username = descriptor.getUsername();
+ String password = descriptor.getPassword();
+ String scheme = descriptor.getScheme();
+ String prompt = descriptor.getPrompt();
+
+ RequestIdentifier id = new RequestIdentifier( host, port, protocol,
scheme, prompt );
+ TransitAuthenticator ta = new TransitAuthenticatorImpl( username,
password );
+ DelegatingAuthenticator da = DelegatingAuthenticator.getInstance();
+ da.addTransitAuthenticator( ta, id );
+ }
+
+ //
------------------------------------------------------------------------
// ResourceHost
//
------------------------------------------------------------------------


Added:
development/main/transit/core/handler/src/main/net/dpml/transit/host/HostDescriptor.java
==============================================================================
--- (empty file)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/host/HostDescriptor.java
Wed May 4 14:32:06 2005
@@ -0,0 +1,256 @@
+/*
+ * 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.host;
+
+import java.util.prefs.Preferences;
+import java.util.prefs.PreferenceChangeEvent;
+import java.util.prefs.PreferenceChangeListener;
+import java.util.EventListener;
+import java.util.EventObject;
+
+import net.dpml.transit.event.EventProducer;
+
+/**
+ * Resource host description used to describe the persistent state of a
+ * host. The class maintains synchronization with underlying preferences
+ * such that changes to preferences are reflected in the instances of this
+ * class. Change notification is the responsibility of a management
+ * applications - in particular, a management application will typically
+ * apply a series of changes to the underlying preferences following which
+ * single change notification event will be raised
+ */
+public class HostDescriptor extends EventProducer implements
PreferenceChangeListener
+{
+ //
------------------------------------------------------------------------
+ // state
+ //
------------------------------------------------------------------------
+
+ private Preferences m_preferences;
+
+ //
------------------------------------------------------------------------
+ // constructor
+ //
------------------------------------------------------------------------
+
+ /**
+ * Create a resource host descriptor using a supplied preference node.
+ *
+ * @param prefs a resource host preferences node
+ */
+ public HostDescriptor( Preferences prefs )
+ {
+ m_preferences = prefs;
+ prefs.addPreferenceChangeListener( this );
+ }
+
+ public void finalize()
+ {
+ if( null != m_preferences )
+ {
+ try
+ {
+ m_preferences.removePreferenceChangeListener( this );
+ }
+ catch( Throwable e )
+ {
+ // ignore
+ }
+ finally
+ {
+ m_preferences = null;
+ }
+ }
+ }
+
+ //
------------------------------------------------------------------------
+ // PreferenceChangeListener
+ //
------------------------------------------------------------------------
+
+ public void preferenceChange( PreferenceChangeEvent event )
+ {
+ String key = event.getKey();
+ if( "modified".equals( key ) )
+ {
+ fireChangeNotification();
+ }
+ }
+
+ //
------------------------------------------------------------------------
+ // ResourceHostDescriptor
+ //
------------------------------------------------------------------------
+
+ public void fireChangeNotification()
+ {
+ HostDescriptorChangeEvent event = new HostDescriptorChangeEvent(
this );
+ enqueueEvent( event );
+ }
+
+ public void addHostDescriptorChangeListener(
HostDescriptorChangeListener listener )
+ {
+ super.addListener( listener );
+ }
+
+ public void removeHostDescriptorChangeListener(
HostDescriptorChangeListener listener )
+ {
+ super.removeListener( listener );
+ }
+
+ protected void processEvent( EventObject event )
+ {
+ if( event instanceof HostDescriptorChangeEvent )
+ {
+ HostDescriptorChangeEvent e = (HostDescriptorChangeEvent) event;
+ EventListener[] listeners = listeners();
+ for( int i=0; i<listeners.length; i++ )
+ {
+ HostDescriptorChangeListener listener =
(HostDescriptorChangeListener) listeners[i];
+ listener.hostChanged( e );
+ }
+ }
+ }
+
+ /**
+ * Return the name of the resource host. The value returned may be used
to uniquely
+ * identify the host within the set of hosts managed within Transit.
+ */
+ public String getHostName()
+ {
+ return m_preferences.name();
+ }
+
+ /**
+ * Return the host handler classname.
+ * @return the classname of the resource host handler
+ */
+ public String getClassname()
+ {
+ return m_preferences.get( "classname",
"net.dpml.transit.host.ClassicResourceHost" );
+ }
+
+ /**
+ * Return the path defining the host base url.
+ * @return the base url path
+ */
+ public String getBasePath()
+ {
+ return m_preferences.get( "base", null );
+ }
+
+ /**
+ * Return index url path.
+ * @return the url path
+ */
+ public String getIndexPath()
+ {
+ return m_preferences.get( "index", null );
+ }
+
+ /**
+ * Return the host priority.
+ * @return the priority
+ */
+ public int getPriority()
+ {
+ return m_preferences.getInt( "priority", 10 );
+ }
+
+ /**
+ * Return the enabled status.
+ * @return TRUE if enabled
+ */
+ public boolean getEnabled()
+ {
+ return m_preferences.getBoolean( "enabled", true );
+ }
+
+ /**
+ * Return the trusted status.
+ * @return TRUE if trusted
+ */
+ public boolean getTrusted()
+ {
+ return m_preferences.getBoolean( "trusted", false );
+ }
+
+ /**
+ * Return the username
+ * @return the username
+ */
+ public String getUsername()
+ {
+ return m_preferences.get( "username", "" );
+ }
+
+ /**
+ * Return the password
+ * @return the password
+ */
+ public String getPassword()
+ {
+ return m_preferences.get( "password", "" );
+ }
+
+ /**
+ * Return the authentication scheme.
+ * @return the schme
+ */
+ public String getScheme()
+ {
+ return m_preferences.get( "scheme", "" );
+ }
+
+ /**
+ * Return the authentication prompt.
+ * @return the scheme
+ */
+ public String getPrompt()
+ {
+ return m_preferences.get( "prompt", "" );
+ }
+
+ /**
+ * Return the resolver classname.
+ * @return the classname of the resolver
+ */
+ public String getResolverClassname()
+ {
+ return m_preferences.get( "resolver",
"net.dpml.transit.layout.ClassicResolver" );
+ }
+
+ /**
+ * Return the last modified value. If the value is 0 the host descriptor
is assumed to
+ * in transition (e.g. editing in a management system). If the value if
greater than 0
+ * then we consider the host descriptor as operational.
+ *
+ * @return the classname of the resolver
+ */
+ public long getLastModified()
+ {
+ return m_preferences.getLong( "modified", 0 );
+ }
+
+ /**
+ * Return a string representation of this host.
+ * @return the representation
+ */
+ public String toString()
+ {
+ return "[HOST:" + m_preferences.name() + "] " + m_preferences;
+ }
+
+}

Added:
development/main/transit/core/handler/src/main/net/dpml/transit/host/HostDescriptorChangeEvent.java
==============================================================================
--- (empty file)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/host/HostDescriptorChangeEvent.java
Wed May 4 14:32:06 2005
@@ -0,0 +1,38 @@
+/*
+ * 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.host;
+
+import java.util.EventObject;
+
+public class HostDescriptorChangeEvent extends EventObject
+{
+ private final HostDescriptor m_descriptor;
+
+ public HostDescriptorChangeEvent( HostDescriptor source )
+ {
+ super( source );
+
+ m_descriptor = source;
+ }
+
+ public HostDescriptor getDescriptor()
+ {
+ return m_descriptor;
+ }
+}

Added:
development/main/transit/core/handler/src/main/net/dpml/transit/host/HostDescriptorChangeListener.java
==============================================================================
--- (empty file)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/host/HostDescriptorChangeListener.java
Wed May 4 14:32:06 2005
@@ -0,0 +1,26 @@
+/*
+ * 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.host;
+
+import java.util.EventListener;
+
+public interface HostDescriptorChangeListener extends EventListener
+{
+ void hostChanged( HostDescriptorChangeEvent event );
+}

Added:
development/main/transit/core/handler/src/main/net/dpml/transit/host/PreferencesResourceManager.java
==============================================================================
--- (empty file)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/host/PreferencesResourceManager.java
Wed May 4 14:32:06 2005
@@ -0,0 +1,389 @@
+/*
+ * 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.host;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.net.URL;
+import java.util.prefs.Preferences;
+import java.util.prefs.BackingStoreException;
+import java.util.jar.JarFile;
+import java.util.zip.ZipEntry;
+import java.util.Enumeration;
+import java.util.Map;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.Date;
+import java.lang.reflect.Constructor;
+
+import net.dpml.lang.NullArgumentException;
+
+import net.dpml.transit.Transit;
+import net.dpml.transit.cache.CacheHandler;
+import net.dpml.transit.monitors.Monitor;
+import net.dpml.transit.monitors.SystemMonitor;
+import net.dpml.transit.TransitException;
+import net.dpml.transit.util.Util;
+import net.dpml.transit.layout.LocationResolver;
+import net.dpml.transit.layout.ClassicResolver;
+
+/**
+ * The PreferencesResourceManager overrides the StandardResourceManager
stategy
+ * concerning cache handler creation. It is intended that this class and the
+ * standard handler would be merged down to a single manager. Prefernces
used
+ * by the manager concerning cache setting are resolved using the following:
+ * <pre>
+ * Preferences userPrefs = Preferences.userNodeForPackage(
CacheHandler.class );
+ * Preferences sysPrefs = Preferences.systemNodeForPackage(
CacheHandler.class );
+ *</pre>
+ * System preferences serve as installation defaults. User preferences are
+ * used to hold modifications. The entention is to ensure that we have a
viable
+ * working set of preferences under the system prefs that we can revert to if
+ * necessary.
+ */
+public class PreferencesResourceManager extends StandardResourceManager
+{
+
//--------------------------------------------------------------------------
+ // static
+
//--------------------------------------------------------------------------
+
+ /**
+ * Default priority string.
+ */
+ private static final String DEFAULT_PRIORITY_STRING = "10";
+
+ /**
+ * True.
+ */
+ private static final String TRUE_VALUE = "true";
+
+
//--------------------------------------------------------------------------
+ // state
+
//--------------------------------------------------------------------------
+
+ private final SystemMonitor m_monitor;
+
+ private final Preferences m_system;
+ private final Preferences m_user;
+
+ private final LocationResolver m_resolver;
+
+ private final Map m_hosts = new Hashtable();
+
+
//--------------------------------------------------------------------------
+ // constructor
+
//--------------------------------------------------------------------------
+
+ /**
+ * Creation of a new resource manager.
+ * @param authorative the authorative base url
+ * @param monitor the internal monitor
+ * @exception IOException if an io error occurs
+ * @exception TransitException if a transit system error occurs
+ */
+ public PreferencesResourceManager( URL authorative, SystemMonitor
monitor )
+ throws TransitException, IOException
+ {
+ super( authorative, monitor );
+ m_monitor = monitor;
+ m_system = Preferences.systemNodeForPackage( ResourceManager.class );
+ m_user = Preferences.userNodeForPackage( ResourceManager.class );
+ String version = m_system.get( "install", null );
+ if( null == version )
+ {
+ setupInitialPreferences();
+ String date = new Date().toString();
+ m_system.put( "install", date ); // used as a flag
+ }
+ m_resolver = createResolver();
+ }
+
+
//--------------------------------------------------------------------------
+ // implementation
+
//--------------------------------------------------------------------------
+
+ /**
+ * Creation of a new cache handler.
+ * @return the cache handler
+ * @exception IOException if an io error occurs
+ * @exception TransitException if a transit system error occurs
+ */
+ public CacheHandler createCacheHandler()
+ throws TransitException, IOException
+ {
+ Preferences cacheSystemPrefs = getSystemCacheNode();
+ Preferences cacheUserPrefs = getUserCacheNode();
+
+ String classname =
+ System.getProperty(
+ CacheHandler.CACHE_CLASS_KEY,
+ cacheUserPrefs.get(
+ "classname",
+ cacheSystemPrefs.get(
+ "classname",
+ TRANSIT_CACHE_DEFAULT_HANDLER_CLASSNAME ) ) );
+ return createCacheHandler( classname );
+ }
+
+ /**
+ * Creation of a new cache handler using a supplied class.
+ * @param classname the CacheHandler classname.
+ * @return the cache handler
+ * @exception IOException if an io error occurs
+ * @exception TransitException if a transit system error occurs
+ */
+ protected CacheHandler createCacheHandler( String classname )
+ throws TransitException, IOException
+ {
+ try
+ {
+ Class cls = getClass().getClassLoader().loadClass( classname );
+ Class[] params = new Class[]{
+ Monitor.class,
+ LocationResolver.class};
+ Object[] args = new Object[]{
+ m_monitor,
+ m_resolver};
+ Constructor cons = cls.getConstructor( params );
+ return (CacheHandler) cons.newInstance( args );
+ }
+ catch( Exception e )
+ {
+ final String error =
+ "Unable to create CacheHandler using ["
+ + classname
+ + "].";
+ throw new TransitException( error, e );
+ }
+ }
+
+ private LocationResolver createResolver()
+ {
+ Preferences cacheSystemPrefs = getSystemCacheNode();
+ Preferences cacheUserPrefs = getUserCacheNode();
+
+ String classname =
+ System.getProperty(
+ CacheHandler.CACHE_CLASS_KEY,
+ cacheUserPrefs.get(
+ "resolver",
+ cacheSystemPrefs.get(
+ "resolver",
+ TRANSIT_CACHE_DEFAULT_RESOLVER_CLASSNAME ) ) );
+ try
+ {
+ Class cls = getClass().getClassLoader().loadClass( classname );
+ return (LocationResolver) cls.newInstance();
+ }
+ catch( Exception e )
+ {
+ return new ClassicResolver(); // Niclas: Should we throw
exception instead???
+ }
+ }
+
+ //
+ // preferences setup
+ //
+
+ private Preferences getUserHostNode( String key )
+ {
+ return getUserHostNode().node( key );
+ }
+
+ private Preferences getUserHostNode()
+ {
+ return Preferences.userNodeForPackage( ResourceHost.class );
+ }
+
+ private Preferences getSystemCacheNode()
+ {
+ return Preferences.systemNodeForPackage( CacheHandler.class );
+ }
+
+ private Preferences getUserCacheNode()
+ {
+ return Preferences.userNodeForPackage( CacheHandler.class );
+ }
+
+ private void setupInitialPreferences() throws TransitException
+ {
+ try
+ {
+ createDefaultCachePreferences();
+ createDefaultResourceHostPreferences();
+ }
+ catch( BackingStoreException e )
+ {
+ final String error =
+ "Unable to resolve transit preferences due to a backing store
error.";
+ throw new TransitException( error, e );
+ }
+ catch( Exception e )
+ {
+ final String error =
+ "Unable to resolve transit preferences due to an unexpected
error.";
+ throw new TransitException( error, e );
+ }
+ }
+
+ private void createDefaultCachePreferences() throws IOException,
BackingStoreException
+ {
+ Preferences systemCachePrefs = getSystemCacheNode();
+ ClassLoader classloader = Transit.class.getClassLoader();
+ URL resource = classloader.getResource(
"transit/authority/cache.properties" );
+ Properties properties = Util.readProps( resource );
+ String location = properties.getProperty( CacheHandler.CACHE_KEY );
+ if( null != location )
+ {
+ systemCachePrefs.put( "location", location );
+ }
+ String classname = properties.getProperty(
CacheHandler.CACHE_CLASS_KEY );
+ if( null != classname )
+ {
+ systemCachePrefs.put( "classname", classname );
+ }
+ String resolver = properties.getProperty(
CacheHandler.RESOLVER_CLASS_KEY );
+ if( null != resolver )
+ {
+ systemCachePrefs.put( "resolver", resolver );
+ }
+ }
+
+ private void createDefaultResourceHostPreferences() throws IOException,
BackingStoreException
+ {
+ ClassLoader classloader = Transit.class.getClassLoader();
+ JarFile jar = getTransitJarFile();
+ Enumeration entries = jar.entries();
+ while( entries.hasMoreElements() )
+ {
+ ZipEntry entry = (ZipEntry) entries.nextElement();
+ String name = entry.getName();
+ if( name.endsWith( ".host" ) )
+ {
+ int n = name.lastIndexOf( "/" );
+ int m = name.lastIndexOf( "." );
+ String shortname = name.substring( n+1, m );
+ URL resource = classloader.getResource( name );
+ createResourceHostPreferences( shortname, resource );
+ }
+ }
+ }
+
+ private JarFile getTransitJarFile() throws IOException
+ {
+ URL url =
Transit.class.getProtectionDomain().getCodeSource().getLocation();
+ File file = convertToFile( url );
+ return new JarFile( file );
+ }
+
+ private void createResourceHostPreferences( String name, URL hostDef )
throws TransitException
+ {
+ if( null == hostDef )
+ {
+ throw new NullArgumentException( "hostDef" );
+ }
+ if( null == name )
+ {
+ throw new NullArgumentException( "name" );
+ }
+
+ try
+ {
+ Properties props = Util.readProps( hostDef );
+ String base = Util.getProperty( props,
"dpml.transit.resourcehost.base", null );
+ if( base == null )
+ {
+ final String error =
+ "Invalid host defintion (no base url declaration)."
+ + "\nHost Definition Resource: " + hostDef;
+ throw new IllegalArgumentException( error );
+ }
+ String key = "dpml.transit.resourcehost.class";
+ String def = "net.dpml.transit.host.ClassicResourceHost";
+ String classname = Util.getProperty( props, key, def );
+ String index = Util.getProperty( props,
"dpml.transit.resourcehost.knowngroups", null );
+
+ String priorityText =
+ Util.getProperty( props, "dpml.transit.resourcehost.priority",
DEFAULT_PRIORITY_STRING );
+ if( "".equals( priorityText ) )
+ {
+ priorityText = DEFAULT_PRIORITY_STRING;
+ }
+ int priority = Integer.parseInt( priorityText );
+ String username = Util.getProperty( props,
"dpml.transit.resourcehost.username", "" );
+ String password = Util.getProperty( props,
"dpml.transit.resourcehost.password", "" );
+ String prompt = Util.getProperty( props,
"dpml.transit.resourcehost.prompt", "" );
+ String scheme = Util.getProperty( props,
"dpml.transit.resourcehost.scheme", "" );
+ String resolverclass =
+ Util.getProperty( props, "dpml.transit.resourcehost.resolver",
"net.dpml.transit.layout.ClassicResolver" );
+ boolean enabled =
+ Util.getProperty(
+ props, "dpml.transit.resourcehost.enabled", TRUE_VALUE
).equalsIgnoreCase( TRUE_VALUE );
+ boolean trusted =
+ Util.getProperty(
+ props, "dpml.transit.resourcehost.trusted", "false"
).equalsIgnoreCase( TRUE_VALUE );
+
+ Preferences prefs = getUserHostNode( name );
+ prefs.put( "classname", classname );
+ prefs.put( "base", base );
+
+ if( null != index )
+ {
+ prefs.put( "index", index );
+ }
+ prefs.putInt( "priority", priority );
+ prefs.putBoolean( "enabled", enabled );
+ prefs.putBoolean( "trusted", trusted );
+ prefs.put( "username", username );
+ prefs.put( "password", password ); // TODO: needs to be encoded
+ prefs.put( "scheme", scheme );
+ prefs.put( "resolver", resolverclass );
+ prefs.putBoolean( "available", true );
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "Unexpected error occured while attempting to construct a
default host preferences."
+ + "\nHost Name: " + name
+ + "\nResource URL: " + hostDef;
+ throw new TransitException( error, e );
+ }
+ }
+
+ private File convertToFile( URL url ) throws IOException
+ {
+ String protocol = url.getProtocol();
+ if( "file".equals( protocol ) )
+ {
+ String spec = url.toExternalForm();
+ String s = spec.substring( 6 );
+ return new File( s );
+ }
+ else
+ {
+ final String error =
+ "Don't know how to convert the '" + protocol + "' protocol to
a file.";
+ throw new IOException( error );
+ }
+ }
+}
+

Modified:
development/main/transit/core/handler/src/main/net/dpml/transit/host/ResourceHost.java
==============================================================================
---
development/main/transit/core/handler/src/main/net/dpml/transit/host/ResourceHost.java
(original)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/host/ResourceHost.java
Wed May 4 14:32:06 2005
@@ -34,7 +34,7 @@
*/
public interface ResourceHost
{
- /** Downloa ds the given artifact to the directory indicated.
+ /** Downloads the given artifact to the directory indicated.
* <p>
* The cachedir argument is the root cache directory, and the
ResourceHost
* class is responsible for the creation of the directory structure of
the
@@ -83,7 +83,7 @@
/** Returns the hostname of the resource host.
*
* <p>
- * This does not include any of the path, but do include any port
number
+ * This does not include any of the path, but does include any port
number
* of this resource host.
* </p>
* @return the hostname

Modified:
development/main/transit/core/handler/src/main/net/dpml/transit/host/ResourceHostFactory.java
==============================================================================
---
development/main/transit/core/handler/src/main/net/dpml/transit/host/ResourceHostFactory.java
(original)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/host/ResourceHostFactory.java
Wed May 4 14:32:06 2005
@@ -102,6 +102,7 @@
* anchor url.
* @param authorative the authorative anchor
* @param monitor the bootstrap monitor
+ * @param flag TRUE if preferences are enabled
*/
ResourceHostFactory( URL authorative, SystemMonitor monitor )
{
@@ -116,12 +117,19 @@
/**
* Create a set of resource hosts relative to the information optained at
the
* authorative anchor.
+ *
+ * <p>
+ * If preferences based resolution is enabled, resource hosts will be
resolved
+ * using the java.util.prefs package otherwise the following strategy
will be
+ * applied.
+ * </p>
+ *
* <p>
* The implementation will attempt to locate a hosts.xml
* at the authorative location and if available will resolve host
defintions
* and return. Otherwise the behaviour is dependent on the type of
authority - if
* the authority url protocol is "file:" then property based host
descriptors will
- * be read from the [authorative]/hosts direrectory. All files in the
directory
+ * be read from the [authorative]/hosts directory. All files in the
directory
* will be considered. If the a property based host file does not contain
the property
* declaration "dpml.transit.resourcehost.base" the file not be
processed. If the
* authorative url is not the "file:" protocol then the implementation
will attempt

Added:
development/main/transit/core/handler/src/main/net/dpml/transit/host/ResourceHostHelper.java
==============================================================================
--- (empty file)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/host/ResourceHostHelper.java
Wed May 4 14:32:06 2005
@@ -0,0 +1,254 @@
+/*
+ * Copyright 2004 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.host;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+
+import java.net.URL;
+import java.net.MalformedURLException;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Properties;
+import java.util.prefs.Preferences;
+
+import net.dpml.lang.NullArgumentException;
+
+import net.dpml.transit.Transit;
+import net.dpml.transit.TransitException;
+
+import net.dpml.transit.layout.LocationResolver;
+
+import net.dpml.transit.monitors.SystemMonitor;
+
+import net.dpml.transit.util.Util;
+
+/**
+ * Internal class that handles the creation of resource hosts based on an
XML host
+ * destriptor or property files.
+ *
+ * TODO: handing of know groups is currently dissabled as this was creating
more than
+ * justifiable grief while putting this stuff together.
+ */
+public class ResourceHostHelper
+{
+ //
------------------------------------------------------------------------
+ // static
+ //
------------------------------------------------------------------------
+
+ /**
+ * True.
+ */
+ private static final String TRUE_VALUE = "true";
+
+ /**
+ * Filename of the remote file index.
+ */
+ private static final String REMOTE_LIST_FILENAME = "index.lst";
+
+ /**
+ * File protocol name length.
+ */
+ private static final int FILE_PROTOCOL_LENGTH = 5;
+
+ /**
+ * Default priority.
+ */
+ static final int DEFAULT_HOST_PRIORITY = 10;
+
+ /**
+ * Default priority string.
+ */
+ private static final String DEFAULT_PRIORITY_STRING = "10";
+
+ //
------------------------------------------------------------------------
+ // constructor
+ //
------------------------------------------------------------------------
+
+ /**
+ * Static utility class.
+ */
+ private ResourceHostHelper()
+ {
+ }
+
+ //
------------------------------------------------------------------------
+ // static utilities
+ //
------------------------------------------------------------------------
+
+ /**
+ * Utility method used to construct a new resource host instance.
+ * @param preferences the preferences instance
+ * @exception TransitException if a construction error occurs
+ */
+ public static ResourceHost createResourceHost( HostDescriptor descriptor
)
+ throws TransitException
+ {
+ String classname = descriptor.getClassname();
+ try
+ {
+ Class clazz = getHostClass( classname );
+ Constructor cons = clazz.getConstructor( new Class[]{
HostDescriptor.class } );
+ return (ResourceHost) cons.newInstance( new Object[]{ descriptor
} );
+ }
+ catch( ClassNotFoundException e )
+ {
+ final String error =
+ "The resource host factory classname ["
+ + classname
+ + "] is unknown.";
+ throw new TransitException( error );
+ }
+ catch( NoSuchMethodException e )
+ {
+ final String error =
+ "The resource host factory class ["
+ + classname
+ + "] does not declare the required constructor.";
+ throw new TransitException( error );
+ }
+ catch( IllegalAccessException e )
+ {
+ final String error =
+ "The resource host factory class ["
+ + classname
+ + "] is not accessible.";
+ throw new TransitException( error );
+ }
+ catch( IllegalArgumentException e )
+ {
+ final String error =
+ "The resource host factory class ["
+ + classname
+ + "] could not be established due to an internal error.";
+ throw new TransitException( error, e );
+ }
+ catch( InstantiationException e )
+ {
+ final String error =
+ "The resource host factory class ["
+ + classname
+ + "] could not be instantiated.";
+ throw new TransitException( error, e );
+ }
+ catch( InvocationTargetException e )
+ {
+ final String error =
+ "The resource host factory class ["
+ + classname
+ + "] raised an unexpected error during instantiation.";
+ throw new TransitException( error, e.getTargetException() );
+ }
+ }
+
+ /**
+ * Return the class relative a supplied filename using this class as the
+ * reference classloader.
+ * @param classname the classname of the class to load
+ * @return the class
+ * @exception ClassNotFoundException if the class cannot be found
+ */
+ private static Class getHostClass( String classname ) throws
ClassNotFoundException
+ {
+ return ResourceHostHelper.class.getClassLoader().loadClass(
classname );
+ }
+
+ public static LocationResolver createResolver( String classname )
+ throws TransitException
+ {
+ try
+ {
+ Class cls = ResourceHostHelper.class.getClassLoader().loadClass(
classname );
+ return (LocationResolver) cls.newInstance();
+ }
+ catch( ClassNotFoundException e )
+ {
+ throw new TransitException( "Specified resolver class can not be
found: " + classname );
+ }
+ catch( ClassCastException e )
+ {
+ throw new TransitException( "Specified resolver classname does
not implement net.dpml.transit.handler.LocationResolver : " + classname );
+ }
+ catch( Exception e )
+ {
+ throw new TransitException( "Unknown exception: " + classname, e
);
+ }
+ }
+
+ /**
+ * 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
+ */
+ public static String[] getKnownGroups( URL href ) throws TransitException
+ {
+ if( href != null )
+ {
+ try
+ {
+ return Util.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];
+ }
+ }
+
+ /**
+ * Return a url using the supplied url as anchor for the supplied path.
+ * @param anchor the anchor url
+ * @param path the relative path
+ * @return the resolved absolute url
+ * @exception TransitException if an error occurs in url creation
+ */
+ private static URL getRelativeURL( URL anchor, String path ) throws
TransitException
+ {
+ try
+ {
+ return new URL( anchor, path );
+ }
+ catch( MalformedURLException mue )
+ {
+ final String error =
+ "An error occured while attempting to construct a new url
using the path ["
+ + path
+ + "] and base url ["
+ + anchor
+ + "].";
+ throw new TransitException( error, mue );
+ }
+ }
+}

Modified:
development/main/transit/core/handler/src/main/net/dpml/transit/host/ResourceManager.java
==============================================================================
---
development/main/transit/core/handler/src/main/net/dpml/transit/host/ResourceManager.java
(original)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/host/ResourceManager.java
Wed May 4 14:32:06 2005
@@ -41,6 +41,12 @@
String TRANSIT_RESOURCE_MANAGER_CLASSNAME =
"net.dpml.transit.host.StandardResourceManager";

+ /**
+ * The default resource manager classname key.
+ */
+ String TRANSIT_PREFS_RESOURCE_MANAGER_CLASSNAME =
+ "net.dpml.transit.host.PreferencesResourceManager";
+
/**
* Return the cache handler.
* @exception IOException if an io error occurs

Modified:
development/main/transit/core/handler/src/main/net/dpml/transit/host/StandardResourceManager.java
==============================================================================
---
development/main/transit/core/handler/src/main/net/dpml/transit/host/StandardResourceManager.java
(original)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/host/StandardResourceManager.java
Wed May 4 14:32:06 2005
@@ -56,13 +56,13 @@
/**
* The default cache handler classname.
*/
- private static final String TRANSIT_CACHE_DEFAULT_HANDLER_CLASSNAME =
+ protected static final String TRANSIT_CACHE_DEFAULT_HANDLER_CLASSNAME =
"net.dpml.transit.cache.FileCacheHandler";

/**
* The default cache handler classname.
*/
- private static final String TRANSIT_CACHE_DEFAULT_RESOLVER_CLASSNAME =
+ protected static final String TRANSIT_CACHE_DEFAULT_RESOLVER_CLASSNAME =
"net.dpml.transit.layout.ClassicResolver";

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

Added:
development/main/transit/core/handler/src/main/net/dpml/transit/images/cache.jpg
==============================================================================
Binary file. No diff available.

Added:
development/main/transit/core/handler/src/main/net/dpml/transit/images/dpml.gif
==============================================================================
Binary file. No diff available.

Added:
development/main/transit/core/handler/src/main/net/dpml/transit/images/http.png
==============================================================================
Binary file. No diff available.

Added:
development/main/transit/core/handler/src/main/net/dpml/transit/images/item.gif
==============================================================================
Binary file. No diff available.

Added:
development/main/transit/core/handler/src/main/net/dpml/transit/images/network.png
==============================================================================
Binary file. No diff available.

Added:
development/main/transit/core/handler/src/main/net/dpml/transit/images/password.png
==============================================================================
Binary file. No diff available.

Added:
development/main/transit/core/handler/src/main/net/dpml/transit/prefs/CachePanel.java
==============================================================================
--- (empty file)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/prefs/CachePanel.java
Wed May 4 14:32:06 2005
@@ -0,0 +1,321 @@
+/*
+ * 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.prefs;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.event.ActionListener;
+import java.awt.event.ActionEvent;
+import java.awt.FlowLayout;
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Insets;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Map;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.prefs.Preferences;
+import java.util.prefs.PreferenceChangeListener;
+import java.util.prefs.PreferenceChangeEvent;
+
+import javax.swing.Action;
+import javax.swing.AbstractAction;
+import javax.swing.BoxLayout;
+import javax.swing.JDialog;
+import javax.swing.JTable;
+import javax.swing.JScrollPane;
+import javax.swing.JButton;
+import javax.swing.JPanel;
+import javax.swing.JLabel;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.CompoundBorder;
+import javax.swing.border.TitledBorder;
+import javax.swing.table.TableColumnModel;
+import javax.swing.table.TableColumn;
+import javax.swing.table.DefaultTableColumnModel;
+import javax.swing.JFileChooser;
+
+import net.dpml.transit.Transit;
+import net.dpml.transit.adapter.ExceptionHelper;
+import net.dpml.transit.cache.CacheHandler;
+import net.dpml.transit.host.ResourceManager;
+import net.dpml.transit.util.Util;
+
+
+/**
+ * Control panel for editing the cache preferences.
+ *
+ * @author <a href="mailto:mcconnell AT osm.net";>OSM</a>
+ */
+public class CachePanel extends JPanel implements PreferenceChangeListener,
PropertyChangeListener
+{
+ //--------------------------------------------------------------
+ // static
+ //--------------------------------------------------------------
+
+ static EmptyBorder border5 = new EmptyBorder( 5, 5, 5, 5);
+
+ //--------------------------------------------------------------
+ // state
+ //--------------------------------------------------------------
+
+ private final JDialog m_parent;
+ private JLabel m_label;
+ private JButton m_ok;
+ private JButton m_revert;
+
+ private File m_target;
+
+ private Preferences m_cachePrefs;
+
+ private PropertyChangeSupport m_propertyChangeSupport;
+
+ //--------------------------------------------------------------
+ // constructor
+ //--------------------------------------------------------------
+
+ public CachePanel( JDialog parent ) throws Exception
+ {
+ m_parent = parent;
+ m_propertyChangeSupport = new PropertyChangeSupport( this );
+
+ m_cachePrefs = Preferences.userNodeForPackage( CacheHandler.class );
+
+ setLayout( new BorderLayout() );
+ setBackground( Color.white );
+
+ File cache = getCurrentCacheFile();
+ String filename = cache.getCanonicalPath();
+
+ JLabel label =
+ IconHelper.createImageIconJLabel(
+ Transit.class.getClassLoader(),
"net/dpml/transit/images/cache.jpg", "Filename", "Directory: " + filename );
+ label.setBorder( new EmptyBorder( 0, 5, 0, 0 ) );
+ m_label = label;
+ m_ok = new JButton( new OKAction( "OK" ) );
+ m_revert = new JButton( new RevertAction( "Undo" ) );
+
+ m_cachePrefs.addPreferenceChangeListener( this );
+
+ if( null == cache )
+ {
+ // setup an error dialog content
+ }
+ else
+ {
+ // create a label containing an icon and the current filename
+
+ JPanel panel = new JPanel();
+ panel.setLayout( new BorderLayout() );
+ panel.setBackground( Color.white );
+ panel.add( label, BorderLayout.WEST );
+ add( panel, BorderLayout.NORTH );
+
+ // add controls for modification of the cache value
+
+ JPanel buttonHolder = new JPanel();
+ buttonHolder.setLayout( new FlowLayout( FlowLayout.RIGHT ) );
+ buttonHolder.add( m_revert );
+ buttonHolder.add( new JButton( new ChangeAction( "Change" ) ) );
+ buttonHolder.add( m_ok );
+ buttonHolder.add( new JButton( new CloseAction( "Cancel" ) ) );
+ buttonHolder.setBorder( new EmptyBorder( 10, 10, 5, 0 ) );
+ buttonHolder.setBackground( Color.white );
+ add( buttonHolder, BorderLayout.SOUTH );
+
+ m_propertyChangeSupport.addPropertyChangeListener( this );
+ }
+ }
+
+ /**
+ * The actions dealing with changes to the dialog raise change events
that
+ * are captured here. This listener checks changes and enables or
disabled
+ * the ok and undo buttons based on the state of controls relative to the
+ * underlying preferences for the cache.
+ */
+ public void propertyChange( PropertyChangeEvent event )
+ {
+ File cache = getCurrentCacheFile();
+ boolean flag = ( false == cache.equals( m_target ) );
+ m_ok.setEnabled( flag );
+ m_revert.setEnabled( flag );
+ }
+
+ public void preferenceChange( PreferenceChangeEvent event )
+ {
+ if( null == m_target )
+ {
+ File cache = getCurrentCacheFile();
+ String path = convertToPath( cache );
+ String text = "Directory: " + path;
+ m_label.setText( text );
+ }
+ }
+
+ private class CloseAction extends AbstractAction
+ {
+ CloseAction( String name )
+ {
+ super( name );
+ }
+
+ public void actionPerformed( ActionEvent event )
+ {
+ m_parent.hide();
+ if( m_target != null )
+ {
+ File cache = getCurrentCacheFile();
+ String filename = convertToPath( cache );
+ final String text = "Directory: " + filename;
+ m_label.setText( text );
+ m_target = null;
+ }
+ m_ok.setEnabled( false );
+ }
+ }
+
+ private class OKAction extends AbstractAction
+ {
+ OKAction( String name )
+ {
+ super( name );
+ setEnabled( false );
+ }
+
+ public void actionPerformed( ActionEvent event )
+ {
+ if( null != m_target )
+ {
+ File file = getCurrentCacheFile();
+ if( false == file.equals( m_target ) )
+ {
+ String path = convertToPath( m_target );
+ m_cachePrefs.put( "location", path );
+ }
+ }
+ m_parent.hide();
+ }
+ }
+
+ private class RevertAction extends AbstractAction
+ {
+ RevertAction( String name )
+ {
+ super( name );
+ setEnabled( false );
+ }
+
+ public void actionPerformed( ActionEvent event )
+ {
+ File old = m_target;
+ m_target = getCurrentCacheFile();
+ String text = "Directory: " + convertToPath( m_target );
+ m_label.setText( text );
+ PropertyChangeEvent e =
+ new PropertyChangeEvent(
+ this, "location", old, m_target);
+ m_propertyChangeSupport.firePropertyChange( e );
+ }
+ }
+
+ private class ChangeAction extends AbstractAction
+ {
+ ChangeAction( String name )
+ {
+ super( name );
+ }
+
+ public void actionPerformed( ActionEvent event )
+ {
+ File file = getCurrentCacheFile();
+ JFileChooser chooser = new JFileChooser();
+ chooser.setFileSelectionMode( JFileChooser.DIRECTORIES_ONLY );
+ chooser.setCurrentDirectory( file );
+ int result = chooser.showOpenDialog( m_parent );
+ if( result == JFileChooser.APPROVE_OPTION )
+ {
+ m_target = chooser.getSelectedFile();
+ String text = "Directory: " + convertToPath( m_target );
+ m_label.setText( text );
+ PropertyChangeEvent e =
+ new PropertyChangeEvent(
+ this, "location", file, m_target );
+ m_propertyChangeSupport.firePropertyChange( e );
+ }
+ }
+ }
+
+ private String convertToPath( File file )
+ {
+ try
+ {
+ return file.getCanonicalPath();
+ }
+ catch( Exception e )
+ {
+ return file.toString();
+ }
+ }
+
+ private File getCurrentCacheFile()
+ {
+ File file = getUserCacheFile();
+ if( null == file )
+ {
+ return getDefaultCacheFile();
+ }
+ else
+ {
+ return file;
+ }
+ }
+
+ private File getUserCacheFile()
+ {
+ String filename = m_cachePrefs.get( "location", null );
+ if( null == filename )
+ {
+ return null;
+ }
+ else
+ {
+ return new File( filename );
+ }
+ }
+
+ private File getDefaultCacheFile()
+ {
+ Preferences node = Preferences.systemNodeForPackage(
CacheHandler.class );
+ String filename = node.get( "location", null );
+ if( null == filename )
+ {
+ throw new IllegalStateException( "missing system location
preference: " + node );
+ }
+ else
+ {
+ return new File( filename );
+ }
+ }
+}

Added:
development/main/transit/core/handler/src/main/net/dpml/transit/prefs/DefaultCellRenderer.java
==============================================================================
--- (empty file)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/prefs/DefaultCellRenderer.java
Wed May 4 14:32:06 2005
@@ -0,0 +1,98 @@
+/*
+ * 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.prefs;
+
+import java.awt.Component;
+import java.awt.Font;
+import javax.swing.ImageIcon;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JTable;
+import javax.swing.SwingConstants;
+import javax.swing.border.EmptyBorder;
+import javax.swing.table.DefaultTableCellRenderer;
+
+class DefaultCellRenderer extends DefaultTableCellRenderer
+{
+
//--------------------------------------------------------------------------
+ // state
+
//--------------------------------------------------------------------------
+
+ private static final EmptyBorder border = new EmptyBorder(1,5,1,3);
+
+
//--------------------------------------------------------------------------
+ // constructor
+
//--------------------------------------------------------------------------
+
+ /**
+ * Creation of a new cell renderer using the default font.
+ */
+ public DefaultCellRenderer( )
+ {
+ }
+
+
//--------------------------------------------------------------------------
+ // implementation
+
//--------------------------------------------------------------------------
+
+ public Component getTableCellRendererComponent(
+ JTable table, Object object, boolean selected, boolean focus, int row,
int column )
+ {
+ JLabel label =
+ (JLabel) super.getTableCellRendererComponent(
+ table, object, selected, focus, row, column );
+ label.setBorder( border );
+ label.setHorizontalAlignment( SwingConstants.LEFT );
+
+ if( object == null )
+ {
+ label.setIcon( null );
+ label.setText( null );
+ return label;
+ }
+
+ if( object instanceof ImageIcon )
+ {
+ label.setText( null );
+ label.setIcon( (ImageIcon) object );
+ return label;
+ }
+ else if( object instanceof Boolean )
+ {
+ JCheckBox checkBox = new JCheckBox();
+ checkBox.setSelected( ((Boolean)object).booleanValue() );
+ if( selected )
+ {
+ checkBox.setForeground(table.getSelectionForeground());
+ checkBox.setBackground(table.getSelectionBackground());
+ }
+ else
+ {
+ checkBox.setForeground(table.getForeground());
+ checkBox.setBackground(table.getBackground());
+ }
+ checkBox.setBorder( new EmptyBorder(0,20,0,10) );
+ checkBox.setHorizontalAlignment(JCheckBox.LEFT);
+ return checkBox;
+ }
+ else
+ {
+ return label;
+ }
+ }
+}
+

Added:
development/main/transit/core/handler/src/main/net/dpml/transit/prefs/HostPanel.java
==============================================================================
--- (empty file)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/prefs/HostPanel.java
Wed May 4 14:32:06 2005
@@ -0,0 +1,499 @@
+/*
+ * 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.prefs;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.event.ActionListener;
+import java.awt.event.ActionEvent;
+import java.awt.FlowLayout;
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Insets;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Date;
+import java.util.Map;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.prefs.Preferences;
+import java.util.prefs.PreferenceChangeListener;
+import java.util.prefs.PreferenceChangeEvent;
+
+import javax.swing.Action;
+import javax.swing.AbstractAction;
+import javax.swing.BoxLayout;
+import javax.swing.JDialog;
+import javax.swing.JTable;
+import javax.swing.JScrollPane;
+import javax.swing.JButton;
+import javax.swing.JPanel;
+import javax.swing.JLabel;
+import javax.swing.JFileChooser;
+import javax.swing.JCheckBox;
+import javax.swing.JRadioButton;
+import javax.swing.JTextField;
+import javax.swing.JComboBox;
+import javax.swing.ImageIcon;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.CompoundBorder;
+import javax.swing.border.TitledBorder;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.table.TableColumnModel;
+import javax.swing.table.TableColumn;
+import javax.swing.table.DefaultTableColumnModel;
+import javax.swing.text.Document;
+
+import net.dpml.transit.Transit;
+import net.dpml.transit.adapter.ExceptionHelper;
+import net.dpml.transit.cache.CacheHandler;
+import net.dpml.transit.host.ResourceManager;
+import net.dpml.transit.host.HostDescriptor;
+import net.dpml.transit.host.ResourceHost;
+import net.dpml.transit.util.Util;
+
+/**
+ * A interactive panel that presents the preferences for a single host.
+ *
+ * @author <a href="mailto:mcconnell AT osm.net";>OSM</a>
+ */
+public class HostPanel extends JPanel implements PreferenceChangeListener,
PropertyChangeListener, DocumentListener
+{
+ //--------------------------------------------------------------
+ // static
+ //--------------------------------------------------------------
+
+ static EmptyBorder border5 = new EmptyBorder( 5, 5, 5, 5);
+
+ //--------------------------------------------------------------
+ // state
+ //--------------------------------------------------------------
+
+ private final JDialog m_parent;
+
+ private JLabel m_label;
+ private JCheckBox m_enabled;
+ private JCheckBox m_trusted;
+ private JTextField m_base;
+
+ private JButton m_ok;
+ private JButton m_revert;
+
+ private Preferences m_hostsPrefs;
+ private Preferences m_hostPrefs;
+
+ private PropertyChangeSupport m_propertyChangeSupport;
+
+ //--------------------------------------------------------------
+ // constructor
+ //--------------------------------------------------------------
+
+ public HostPanel( JDialog parent, String name ) throws Exception
+ {
+ m_parent = parent;
+ m_propertyChangeSupport = new PropertyChangeSupport( this );
+
+ setLayout( new BorderLayout() );
+ setBackground( Color.white );
+ setBorder( new EmptyBorder( 10, 6, 0, 6 ) );
+
+ m_hostsPrefs = Preferences.userNodeForPackage( ResourceHost.class );
+ m_hostPrefs = m_hostsPrefs.node( name ); // TODO: host could have
been removed
+ m_hostPrefs.addPreferenceChangeListener( this );
+
+ HostDescriptor descriptor = new HostDescriptor( m_hostPrefs );
+
+ //
+ // create the dialog label containing the host descriptor name
+ //
+
+ m_label =
+ IconHelper.createImageIconJLabel(
+ Transit.class.getClassLoader(),
"net/dpml/transit/images/network.png", "Host", "Host: " + name );
+
+ m_label.setBorder( new EmptyBorder( 0, 5, 0, 10 ) );
+ JPanel labelPanel = new JPanel();
+ labelPanel.setLayout( new BorderLayout() );
+ labelPanel.setBackground( Color.white );
+ labelPanel.add( m_label, BorderLayout.WEST );
+ labelPanel.setBorder( new EmptyBorder( 10, 6, 10, 6 ) );
+
+ //
+ // create a panel to hold things in the center of the dialog
+ //
+
+ JPanel panel = new JPanel();
+ panel.setLayout( new BoxLayout( panel, BoxLayout.Y_AXIS ) );
+ panel.setBackground( Color.white );
+
+ //
+ // create a box layout for the host base url and groups button
+ // TODO: action support for groups
+ //
+
+ JPanel paths = new JPanel();
+ panel.add( paths );
+ paths.setLayout( new BorderLayout() );
+ paths.setBackground( Color.white );
+ paths.setBorder(
+ new CompoundBorder(
+ new TitledBorder( null, "Base URL", TitledBorder.LEFT,
TitledBorder.TOP), border5 ) );
+
+ m_base = new JTextField( descriptor.getBasePath() );
+ m_base.getDocument().addDocumentListener( this ); // listen for
changes
+ m_base.setBackground( Color.white );
+ JPanel basePanel = new JPanel();
+ basePanel.setLayout( new BorderLayout() );
+ basePanel.setBackground( Color.white );
+ basePanel.setBorder( new EmptyBorder( 0, 0, 0, 30 ) );
+ basePanel.add( m_base, BorderLayout.CENTER );
+
+ JButton knownGroups = new JButton( "Groups" );
+ knownGroups.setEnabled( false );
+ JPanel groupsPanel = new JPanel();
+ groupsPanel.setLayout( new BorderLayout() );
+ groupsPanel.setBackground( Color.white );
+ groupsPanel.add( knownGroups, BorderLayout.EAST );
+
+ paths.add( basePanel, BorderLayout.CENTER );
+ paths.add( groupsPanel, BorderLayout.EAST );
+
+ //
+ // create a box layout to hold the layout strategy and the
credentials
+ //
+
+ JPanel layoutPlusCredentials = new JPanel();
+ layoutPlusCredentials.setLayout( new BoxLayout(
layoutPlusCredentials, BoxLayout.X_AXIS ) );
+ layoutPlusCredentials.setBackground( Color.white );
+ panel.add( layoutPlusCredentials );
+
+ // repository layout strategy
+ // TODO: need to figure out how to get a layout 'friendly name' and
associate
+ // this with a class name.
+
+ JPanel layout = new JPanel();
+ layout.setLayout( new BorderLayout() );
+ layout.setBackground( Color.white );
+ layout.setBorder(
+ new CompoundBorder(
+ new TitledBorder( null, "Repository Layout", TitledBorder.LEFT,
TitledBorder.TOP), border5 ) );
+ layoutPlusCredentials.add( layout );
+
+ JComboBox strategy = new JComboBox( new Object[]{ " Classic Layout "
} );
+ layout.add( strategy, BorderLayout.SOUTH );
+
+ // sign-on credentials
+
+ JPanel credentials = new JPanel();
+ credentials.setLayout( new BoxLayout( credentials, BoxLayout.X_AXIS
) );
+ credentials.setBackground( Color.white );
+ credentials.setBorder(
+ new CompoundBorder(
+ new TitledBorder( null, "Credentials", TitledBorder.LEFT,
TitledBorder.TOP), border5 ) );
+ // TODO: action support for credential settings
+ ImageIcon keysIcon = IconHelper.createImageIcon(
+ Transit.class.getClassLoader(),
"net/dpml/transit/images/password.png", "Credentials" );
+ JLabel keys = new JLabel( keysIcon );
+ JButton settings = new JButton( "Settings" );
+ settings.setEnabled( false );
+ JPanel settingsPanel = new JPanel();
+ settingsPanel.setLayout( new BorderLayout() );
+ settingsPanel.setBackground( Color.white );
+ settingsPanel.add( keys, BorderLayout.WEST );
+ settingsPanel.add( settings, BorderLayout.EAST );
+ credentials.add( settingsPanel );
+ layoutPlusCredentials.add( credentials );
+
+ //
+ // create a box layout for the enabled and trusted checkboxs
+ //
+
+ JPanel holder = new JPanel();
+ holder.setLayout( new BoxLayout( holder, BoxLayout.Y_AXIS ) );
+ holder.setBackground( Color.white );
+ holder.setBorder(
+ new CompoundBorder(
+ new TitledBorder( null, "Parameters", TitledBorder.LEFT,
TitledBorder.TOP), border5 ) );
+ panel.add( holder );
+
+ // add enabled status
+
+ m_enabled = new JCheckBox( new EnableAction( "Enabled" ) );
+ m_enabled.setBackground( Color.white );
+ m_enabled.setSelected( descriptor.getEnabled() );
+
+ JPanel enabledPanel = new JPanel();
+ enabledPanel.setLayout( new BorderLayout() );
+ enabledPanel.setBackground( Color.white );
+ enabledPanel.add( m_enabled, BorderLayout.WEST );
+ enabledPanel.add( m_enabled );
+ holder.add( enabledPanel );
+
+ // add trusted status
+
+ m_trusted = new JCheckBox( new TrustedAction( "Trusted" ) );
+ m_trusted.setBackground( Color.white );
+ m_trusted.setSelected( descriptor.getTrusted() );
+
+ JPanel trustedPanel = new JPanel();
+ trustedPanel.setLayout( new BorderLayout() );
+ trustedPanel.setBackground( Color.white );
+ trustedPanel.add( m_trusted, BorderLayout.WEST );
+ trustedPanel.add( m_trusted );
+ holder.add( trustedPanel );
+
+ //
+ // add commmit/revert controls and assemble the dialog
+ //
+
+ m_ok = new JButton( new OKAction( "OK", this ) );
+ m_revert = new JButton( new RevertAction( "Undo Changes" ) );
+ JPanel buttonHolder = new JPanel();
+ buttonHolder.setLayout( new FlowLayout( FlowLayout.RIGHT ) );
+ buttonHolder.add( m_revert );
+ buttonHolder.add( m_ok );
+ buttonHolder.add( new JButton( new CloseAction( "Cancel" ) ) );
+ buttonHolder.setBorder( new EmptyBorder( 10, 10, 5, 0 ) );
+ buttonHolder.setBackground( Color.white );
+
+ JPanel thing = new JPanel();
+ thing.setLayout( new BorderLayout() );
+ thing.add( panel, BorderLayout.NORTH );
+ thing.setBackground( Color.white );
+
+ add( labelPanel, BorderLayout.NORTH );
+ add( thing , BorderLayout.CENTER );
+ add( buttonHolder, BorderLayout.SOUTH );
+
+ m_propertyChangeSupport.addPropertyChangeListener( this );
+ }
+
+ //--------------------------------------------------------------
+ // PreferenceChangeListener
+ //--------------------------------------------------------------
+
+ public void preferenceChange( PreferenceChangeEvent event )
+ {
+ }
+
+ //--------------------------------------------------------------
+ // PropertyChangeListener
+ //--------------------------------------------------------------
+
+ /**
+ * The actions dealing with changes to the dialog raise change events
that
+ * are captured here. This listener checks changes and enables or
disabled
+ * the ok and undo buttons based on the state of controls relative to the
+ * underlying preferences for this host.
+ */
+ public void propertyChange( PropertyChangeEvent event )
+ {
+ boolean flag = false;
+ {
+ boolean value = m_enabled.isSelected();
+ if( m_hostPrefs.getBoolean( "enabled", true ) != value )
+ {
+ flag = true;
+ }
+ }
+ {
+ boolean value = m_trusted.isSelected();
+ if( m_hostPrefs.getBoolean( "trusted", false ) != value )
+ {
+ flag = true;
+ }
+ }
+ {
+ String path = m_base.getText();
+ if( false == path.equals( m_hostPrefs.get( "base", null ) ) )
+ {
+ flag = true;
+ }
+ }
+ m_ok.setEnabled( flag );
+ m_revert.setEnabled( flag );
+ }
+
+ //--------------------------------------------------------------
+ // DocumentListener
+ //--------------------------------------------------------------
+
+ public void insertUpdate( DocumentEvent event )
+ {
+ fireBaseChangedEvent();
+ }
+
+ public void removeUpdate( DocumentEvent event )
+ {
+ fireBaseChangedEvent();
+ }
+
+ public void changedUpdate( DocumentEvent event )
+ {
+ fireBaseChangedEvent();
+ }
+
+ private void fireBaseChangedEvent()
+ {
+ String path = m_hostPrefs.get( "base", null );
+ PropertyChangeEvent e =
+ new PropertyChangeEvent(
+ m_base, "base", path, m_base.getText() );
+ m_propertyChangeSupport.firePropertyChange( e );
+ }
+
+ //--------------------------------------------------------------
+ // utility classes
+ //--------------------------------------------------------------
+
+ private class EnableAction extends AbstractAction
+ {
+ EnableAction( String name )
+ {
+ super( name );
+ }
+
+ public void actionPerformed( ActionEvent event )
+ {
+ boolean selected = m_enabled.isSelected();
+ PropertyChangeEvent e =
+ new PropertyChangeEvent(
+ this, "enabled", new Boolean( !selected ), new Boolean(
selected ) );
+ m_propertyChangeSupport.firePropertyChange( e );
+ }
+ }
+
+ private class TrustedAction extends AbstractAction
+ {
+ TrustedAction( String name )
+ {
+ super( name );
+ }
+
+ public void actionPerformed( ActionEvent event )
+ {
+ boolean selected = m_trusted.isSelected();
+ PropertyChangeEvent e =
+ new PropertyChangeEvent(
+ this, "trusted", new Boolean( !selected ), new Boolean(
selected ) );
+ m_propertyChangeSupport.firePropertyChange( e );
+ }
+ }
+
+ /**
+ * Action that handles the 'Cancel' dialog button.
+ */
+ private class CloseAction extends AbstractAction
+ {
+ CloseAction( String name )
+ {
+ super( name );
+ }
+
+ public void actionPerformed( ActionEvent event )
+ {
+ m_parent.hide();
+ m_ok.setEnabled( false );
+ }
+ }
+
+ private class OKAction extends AbstractAction
+ {
+ private PropertyChangeListener m_listener;
+
+ OKAction( String name, PropertyChangeListener listener )
+ {
+ super( name );
+ setEnabled( false );
+ m_listener = listener;
+ }
+
+ // TODO: we need a solution in place under which we log
+ // information about preference changes
+
+ public void actionPerformed( ActionEvent event )
+ {
+ m_parent.hide();
+ m_propertyChangeSupport.removePropertyChangeListener( m_listener
);
+ {
+ boolean value = m_enabled.isSelected();
+ if( m_hostPrefs.getBoolean( "enabled", true ) != value )
+ {
+ m_hostPrefs.putBoolean( "enabled", value );
+ }
+ }
+ {
+ boolean value = m_trusted.isSelected();
+ if( m_hostPrefs.getBoolean( "trusted", true ) != value )
+ {
+ m_hostPrefs.putBoolean( "trusted", value );
+ }
+ }
+ {
+ String value = m_base.getText();
+ if( false == value.equals( m_hostPrefs.get( "base", null ) )
)
+ {
+ m_hostPrefs.put( "base", value );
+ }
+ }
+ try
+ {
+ m_hostPrefs.putLong( "modified", new Date().getTime() ); //
trigger event broadcast
+ m_hostPrefs.flush();
+ }
+ catch( Throwable e )
+ {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private class RevertAction extends AbstractAction
+ {
+ RevertAction( String name )
+ {
+ super( name );
+ setEnabled( false );
+ }
+
+ public void actionPerformed( ActionEvent event )
+ {
+ m_enabled.setSelected( m_hostPrefs.getBoolean( "enabled", true )
);
+ m_trusted.setSelected( m_hostPrefs.getBoolean( "trusted", false
) );
+ m_base.setText( m_hostPrefs.get( "base", null ) );
+ try
+ {
+ m_hostPrefs.flush();
+ }
+ catch( Throwable e )
+ {
+ e.printStackTrace();
+ }
+ PropertyChangeEvent e =
+ new PropertyChangeEvent(
+ this, "revert", null, null );
+ m_propertyChangeSupport.firePropertyChange( e );
+ }
+ }
+}

Added:
development/main/transit/core/handler/src/main/net/dpml/transit/prefs/HostsTable.java
==============================================================================
--- (empty file)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/prefs/HostsTable.java
Wed May 4 14:32:06 2005
@@ -0,0 +1,220 @@
+/*
+ * 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.prefs;
+
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.Color;
+
+import javax.swing.JTable;
+import javax.swing.table.TableModel;
+import javax.swing.table.TableColumnModel;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.ListSelectionModel;
+import javax.swing.SwingUtilities;
+
+/**
+ * A table mapping the collection of preference nodes to hosts.
+ */
+public class HostsTable extends JTable implements ListSelectionListener,
FocusListener
+{
+
//--------------------------------------------------------------------------
+ // static
+
//--------------------------------------------------------------------------
+
+ /**
+ * The enabled color.
+ */
+ private static final Color ENABLED_COLOR = new Color( 204, 204, 255 );
+
+ /**
+ * The disabled color.
+ */
+ private static final Color DISABLED_COLOR = new Color( 228, 228, 255 );
+
+ /**
+ * Double-click count.
+ */
+ private static final int TWO = 2;
+
+ /**
+ * Row height.
+ */
+ private static final int ROW_HEIGHT = 18;
+
+
//--------------------------------------------------------------------------
+ // state
+
//--------------------------------------------------------------------------
+
+ /**
+ * The currently selected item if only 1 instance is selected.
+ */
+ private Object m_selection;
+
+ /**
+ * The table data model.
+ */
+ private TableModel m_data;
+
+
//--------------------------------------------------------------------------
+ // constructor
+
//--------------------------------------------------------------------------
+
+ /**
+ * Creation of a new hosts table.
+ * @param entity the entity that this table is presenting
+ * @param data a table model containing the data to layout in view
+ * @param columns the table column model to apply
+ */
+ public HostsTable( TableModel data, TableColumnModel columns )
+ {
+ super( data, columns );
+
+ m_data = data;
+ setShowGrid( false );
+ setRowHeight( ROW_HEIGHT );
+ getTableHeader().setReorderingAllowed( false );
+
+ MouseListener popupListener = new PopupListener();
+ addMouseListener( popupListener );
+ addFocusListener( this );
+ }
+
+
//--------------------------------------------------------------------------
+ // ListSelectionListener
+
//--------------------------------------------------------------------------
+
+ /**
+ * Listens to changes in the selected state of the table and
+ * propergates a <code>ContextEvent</code> referencing this table as
+ * the event's panel when the table selection changes.
+ * @param event a list selection event
+ */
+ public void valueChanged( ListSelectionEvent event )
+ {
+ super.valueChanged( event );
+ if( !event.getValueIsAdjusting() )
+ {
+ ListSelectionModel model = getSelectionModel();
+ synchronized( model )
+ {
+ int n = model.getMinSelectionIndex();
+ if( ( n == model.getMaxSelectionIndex() ) && ( n > -1 ) )
+ {
+ m_selection = m_data.getValueAt( n, -1 );
+ }
+ else if( m_selection != null )
+ {
+ m_selection = null;
+ }
+ }
+ }
+ }
+
+
//--------------------------------------------------------------------------
+ // FocusListener
+
//--------------------------------------------------------------------------
+
+ /**
+ * Handle the focus gained event.
+ * @param event the focus event
+ */
+ public void focusGained( FocusEvent event )
+ {
+ setSelectionBackground( ENABLED_COLOR );
+ }
+
+ /**
+ * Handle the focus lost event.
+ * @param event the focus event
+ */
+ public void focusLost( FocusEvent event )
+ {
+ setSelectionBackground( DISABLED_COLOR );
+ }
+
+ /**
+ * Mouse adapter.
+ */
+ private class PopupListener extends MouseAdapter
+ {
+ /**
+ * Handle a mouse event.
+ * @param event the mouse pressed event
+ */
+ public void mousePressed( MouseEvent event )
+ {
+ handleMouseEvent( event );
+ }
+
+ /**
+ * Handle a mouse event.
+ * @param event the mouse released event
+ */
+ public void mouseReleased( MouseEvent event )
+ {
+ handleMouseEvent( event );
+ }
+ }
+
+ /**
+ * Handle a mouse event within the table.
+ * @param event the mouse event
+ */
+ protected void handleMouseEvent( MouseEvent event )
+ {
+ if( event.isPopupTrigger() )
+ {
+System.out.println( "# POPUP TRIGGER" );
+ int j = rowAtPoint( event.getPoint() );
+ if( j > -1 )
+ {
+ if( !isRowSelected( j ) )
+ {
+ clearSelection();
+ setRowSelectionInterval( j, j );
+ }
+ }
+ else
+ {
+ clearSelection();
+ }
+ }
+ else if( SwingUtilities.isLeftMouseButton( event ) &&
event.getClickCount() == TWO )
+ {
+System.out.println( "# DOUBLE CLICK" );
+ int j = rowAtPoint( event.getPoint() );
+ if( j > -1 )
+ {
+ if( !isRowSelected( j ) )
+ {
+ clearSelection();
+ setRowSelectionInterval( j, j );
+ }
+ }
+ else
+ {
+ clearSelection();
+ }
+ }
+ }
+
+}

Added:
development/main/transit/core/handler/src/main/net/dpml/transit/prefs/HostsTableModel.java
==============================================================================
--- (empty file)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/prefs/HostsTableModel.java
Wed May 4 14:32:06 2005
@@ -0,0 +1,178 @@
+/*
+ * 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.prefs;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeEvent;
+import java.util.Arrays;
+import java.util.List;
+import java.util.LinkedList;
+import java.util.Iterator;
+import java.util.prefs.Preferences;
+import java.util.prefs.NodeChangeListener;
+import java.util.prefs.NodeChangeEvent;
+
+import java.net.URL;
+
+import javax.swing.table.AbstractTableModel;
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+
+import net.dpml.transit.Transit;
+import net.dpml.transit.host.ResourceHost;
+
+/**
+ * Table model used to manage features of an adapter.
+ */
+class HostsTableModel extends AbstractTableModel implements
NodeChangeListener
+{
+
//--------------------------------------------------------------------------
+ // static
+
//--------------------------------------------------------------------------
+
+ /**
+ * Default small icon path.
+ */
+ private static final String ICON_PATH =
"net/dpml/transit/images/item.gif";
+
+ /**
+ * Constant row identifier for the icon.
+ */
+ public static final int ICON = 0;
+
+ /**
+ * Constant row identifier for the name.
+ */
+ public static final int VALUE = 1;
+
+ /**
+ * Number of columns.
+ */
+ private static final int COLUMN_COUNT = 2;
+
+ /**
+ * Default small icon.
+ */
+ private static final Icon FEATURE_ICON =
+ IconHelper.createImageIcon( Transit.class.getClassLoader(), ICON_PATH,
"Features" );
+
+
//--------------------------------------------------------------------------
+ // constructor
+
//--------------------------------------------------------------------------
+
+ /**
+ * Creation of a new feature table model.
+ * @param entity the reference entity
+ */
+ public HostsTableModel( Preferences prefs )
+ {
+ super();
+ prefs.addNodeChangeListener( this );
+ }
+
+
//--------------------------------------------------------------------------
+ // NodeChangeListener
+
//--------------------------------------------------------------------------
+
+ /**
+ * Handle the addition of a host following a preferences node change.
+ *
+ * @param event the node addition event
+ */
+ public void childAdded( NodeChangeEvent event )
+ {
+ fireTableStructureChanged();
+ }
+
+ public void childRemoved( NodeChangeEvent event )
+ {
+ fireTableStructureChanged();
+ }
+
+
//--------------------------------------------------------------------------
+ // HostsTableModel
+
//--------------------------------------------------------------------------
+
+ /**
+ * Returns the number of model columns.
+ * @return int the number of columns maintained by the model
+ */
+ public int getColumnCount()
+ {
+ return COLUMN_COUNT;
+ }
+
+ /**
+ * Returns the number of rows in the model. The value returned is
+ * equivilent to the number of elements in the list backing the model.
+ * @return int the number of rows maintained by the model
+ */
+ public int getRowCount()
+ {
+ try
+ {
+ return getHostPreferences().childrenNames().length;
+ }
+ catch( Throwable e )
+ {
+ return 0;
+ }
+ }
+
+ /**
+ * Returns the feature object at the request column and row combination.
+ * If the col index is out of range the method returns the agent
corresponding
+ * to the row identifier.
+ * @param row the row index
+ * @param col the column index
+ * @return Object
+ */
+ public Object getValueAt( int row, int col )
+ {
+ Object result = "";
+ if( row > getRowCount() )
+ {
+ return result;
+ }
+
+ switch( col )
+ {
+ case ICON :
+ return FEATURE_ICON;
+ default:
+ return getHostAtRow( row );
+ }
+ }
+
+ private String getHostAtRow( int row )
+ {
+ try
+ {
+ String[] names = getHostPreferences().childrenNames();
+ return names[ row ];
+ }
+ catch( Throwable e )
+ {
+ return "";
+ }
+ }
+
+ Preferences getHostPreferences()
+ {
+ return Preferences.userNodeForPackage( ResourceHost.class );
+ }
+}

Added:
development/main/transit/core/handler/src/main/net/dpml/transit/prefs/IconHelper.java
==============================================================================
--- (empty file)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/prefs/IconHelper.java
Wed May 4 14:32:06 2005
@@ -0,0 +1,53 @@
+/*
+ * 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.prefs;
+
+import java.net.URL;
+
+import javax.swing.JLabel;
+import javax.swing.ImageIcon;
+
+/**
+ */
+class IconHelper
+{
+ public static JLabel createImageIconJLabel( ClassLoader classloader,
String path, String description, String text )
+ {
+ ImageIcon icon = createImageIcon( classloader, path, description );
+ JLabel label = new JLabel( text, icon, JLabel.LEFT );
+ return label;
+ }
+
+ public static ImageIcon createImageIcon( ClassLoader classloader, String
path, String description )
+ {
+ URL url = classloader.getResource( path );
+ if( null != url )
+ {
+ return new ImageIcon( url );
+ }
+ else
+ {
+ final String error =
+ "Supplied image icon resource path is unknown ["
+ + path
+ + "].";
+ throw new IllegalArgumentException( error );
+ }
+ }
+}

Added:
development/main/transit/core/handler/src/main/net/dpml/transit/prefs/ResourcePanel.java
==============================================================================
--- (empty file)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/prefs/ResourcePanel.java
Wed May 4 14:32:06 2005
@@ -0,0 +1,412 @@
+/*
+ * Copyright 2004 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.prefs;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.event.ActionListener;
+import java.awt.event.ActionEvent;
+import java.awt.FlowLayout;
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Insets;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Map;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.prefs.Preferences;
+
+import javax.swing.Action;
+import javax.swing.AbstractAction;
+import javax.swing.BoxLayout;
+import javax.swing.JDialog;
+import javax.swing.JTable;
+import javax.swing.JScrollPane;
+import javax.swing.JButton;
+import javax.swing.JPanel;
+import javax.swing.JLabel;
+import javax.swing.ListSelectionModel;
+import javax.swing.JOptionPane;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.CompoundBorder;
+import javax.swing.border.TitledBorder;
+import javax.swing.table.TableColumnModel;
+import javax.swing.table.TableColumn;
+import javax.swing.table.DefaultTableColumnModel;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.event.ListSelectionEvent;
+
+import net.dpml.transit.Transit;
+import net.dpml.transit.adapter.ExceptionHelper;
+import net.dpml.transit.cache.CacheHandler;
+import net.dpml.transit.host.ResourceHost;
+import net.dpml.transit.util.Util;
+
+
+
+/**
+ * Runnable plugin that handles DPML environment setup.
+ *
+ * @author <a href="mailto:mcconnell AT osm.net";>OSM</a>
+ */
+public class ResourcePanel extends JPanel implements ListSelectionListener
+{
+ //--------------------------------------------------------------
+ // static
+ //--------------------------------------------------------------
+
+ static EmptyBorder border5 = new EmptyBorder( 5, 5, 5, 5);
+
+ //--------------------------------------------------------------
+ // state
+ //--------------------------------------------------------------
+
+ private final JDialog m_parent;
+
+ private HostsTable m_table;
+
+ private JButton m_edit;
+ private JButton m_delete;
+
+ private String m_hostName; // selected hostname
+
+ //--------------------------------------------------------------
+ // constructor
+ //--------------------------------------------------------------
+
+ public ResourcePanel( JDialog parent ) throws Exception
+ {
+ m_parent = parent;
+
+ m_edit = new JButton( new EditAction( "Edit" ) );
+ m_delete = new JButton( new DeleteAction( "Delete" ) );
+
+ setLayout( new BorderLayout() );
+ setBorder( new EmptyBorder( 10, 6, 10, 6 ) );
+ setBackground( Color.white );
+
+ JPanel hostPanel = new JPanel();
+ hostPanel.setBackground( Color.white );
+
+ hostPanel.setLayout( new BorderLayout() );
+ TitledBorder tb =
+ new TitledBorder(
+ new EmptyBorder( 0,0,0,0 ), "Resource Hosts", TitledBorder.LEFT,
TitledBorder.TOP );
+ hostPanel.setBorder( new CompoundBorder( tb, border5 ) );
+
+ Preferences hosts = Preferences.userNodeForPackage(
ResourceHost.class );
+ TableColumnModel columns = createHostsColumnModel();
+ HostsTableModel model = new HostsTableModel( hosts );
+ m_table = new HostsTable( model, columns );
+ m_table.setShowVerticalLines( false );
+ m_table.setShowHorizontalLines( false );
+ m_table.getSelectionModel().addListSelectionListener( this );
+
+ JScrollPane scroller = createScrollPanel( m_table );
+ hostPanel.add( scroller, BorderLayout.CENTER );
+ JPanel buttonHolder = new JPanel();
+ buttonHolder.setLayout( new FlowLayout( FlowLayout.RIGHT ) );
+ buttonHolder.add( new JButton( new AddAction( "Add" ) ) );
+ buttonHolder.add( m_edit );
+ buttonHolder.add( m_delete );
+ buttonHolder.setBorder( new EmptyBorder( 10, 10, 5, 0 ) );
+ buttonHolder.setBackground( Color.white );
+ hostPanel.add( buttonHolder, BorderLayout.SOUTH );
+
+ JPanel cachePanel = createCachePanel( parent );
+
+ add( cachePanel, BorderLayout.NORTH );
+ add( hostPanel, BorderLayout.CENTER );
+ }
+
+ private JPanel createCachePanel( JDialog parent )
+ {
+ JLabel label =
+ IconHelper.createImageIconJLabel(
+ ResourcePanel.class.getClassLoader(),
+ "net/dpml/transit/images/cache.jpg",
+ "Properties",
+ "Cache handler properties and settings." );
+ label.setBorder( new EmptyBorder( 0, 5, 0, 0 ) );
+
+ JPanel holder = new JPanel();
+ holder.setLayout( new BoxLayout( holder, BoxLayout.Y_AXIS ) );
+ holder.setBorder( new EmptyBorder( 0, 6, 0, 6 ) );
+ holder.setBackground( Color.white );
+ JPanel cache = new JPanel();
+ cache.setBackground( Color.white );
+ cache.setLayout( new BorderLayout() );
+ cache.add( label, BorderLayout.WEST );
+ cache.setBorder(
+ new CompoundBorder(
+ new TitledBorder( null, "Cache", TitledBorder.LEFT,
TitledBorder.TOP), border5 ) );
+ JButton button = new JButton( new CacheAction( parent, "Cache" ) );
+ JPanel cacheButtonHolder = new JPanel();
+ cacheButtonHolder.setBackground( Color.white );
+ cacheButtonHolder.setLayout( new BorderLayout() );
+ cacheButtonHolder.add( button, BorderLayout.SOUTH );
+ cache.add( cacheButtonHolder, BorderLayout.EAST );
+ holder.add( cache );
+ return holder;
+ }
+
+ private static class CacheAction extends AbstractAction
+ {
+ JDialog m_parent;
+
+ CacheAction( JDialog parent, String name )
+ {
+ super( name );
+ m_parent = parent;
+ }
+
+ public void actionPerformed( ActionEvent event )
+ {
+ try
+ {
+ JDialog dialog = new JDialog( m_parent, true );
+ dialog.setTitle( "Resource Cache" );
+ Dimension size = new Dimension( 400, 160 );
+
+ JPanel frame = new JPanel();
+ frame.setLayout( new BorderLayout() );
+ frame.setBackground( Color.white );
+ frame.setBorder( new EmptyBorder( 10, 6, 0, 6 ) );
+
+ JPanel panel = new CachePanel( dialog );
+ frame.add( panel, BorderLayout.CENTER );
+ dialog.setContentPane( frame );
+ dialog.setSize( size );
+ dialog.setLocationRelativeTo( (Component) event.getSource()
);
+ dialog.setResizable( true );
+ dialog.setVisible(true);
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "Unexpected error while attempting to handle the 'Cache'
action. "
+ + "\nCODEBASE: "
+ +
ResourcePanel.class.getProtectionDomain().getCodeSource().getLocation().toString();
+ String message = ExceptionHelper.packException( error, e,
true );
+ System.err.println( message );
+ }
+ }
+
+ private static class CloseAction extends AbstractAction
+ {
+ private JDialog m_dialog;
+
+ CloseAction( String name, JDialog dialog )
+ {
+ super( name );
+ m_dialog = dialog;
+ }
+
+ public void actionPerformed( ActionEvent event )
+ {
+ m_dialog.hide();
+ }
+ }
+ }
+
+ //--------------------------------------------------------------
+ // utilities
+ //--------------------------------------------------------------
+
+ private static JPanel createLabel( String name )
+ {
+ JLabel label = new JLabel( name );
+ label.setBorder( new EmptyBorder( 10, 10, 10, 10 ) );
+ JPanel panel = new JPanel( new FlowLayout( FlowLayout.LEFT ) );
+ panel.add( label );
+ return panel;
+ }
+
+ /**
+ * Creation of a parameterized scroll pane.
+ * @param view the viewport view
+ * @return the scroll pane wrapping the supplied view
+ */
+ private static JScrollPane createScrollPanel( Component view )
+ {
+ JScrollPane scroller = new JScrollPane();
+ scroller.setVerticalScrollBarPolicy(
+ JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED );
+ scroller.setHorizontalScrollBarPolicy(
+ JScrollPane.HORIZONTAL_SCROLLBAR_NEVER );
+ scroller.getViewport().setBackground( Color.white );
+ scroller.setViewportView( view );
+ return scroller;
+ }
+
+ /**
+ * Utility method to construct the hosts table column model.
+ * @return the table
+ */
+ private static TableColumnModel createHostsColumnModel()
+ {
+ TableColumn iconColumn = new TableColumn( 0, 30, new
DefaultCellRenderer(), null );
+ iconColumn.setHeaderValue("");
+ iconColumn.setMaxWidth( 30 );
+ iconColumn.setMinWidth( 30 );
+ TableColumn hostColumn = new TableColumn( 1, 100, new
DefaultCellRenderer(), null );
+ hostColumn.setHeaderValue("Host");
+ TableColumnModel columnModel = new DefaultTableColumnModel();
+ columnModel.addColumn( iconColumn );
+ columnModel.addColumn( hostColumn );
+ return columnModel;
+ }
+
+ private class AddAction extends AbstractAction
+ {
+ public AddAction( String name )
+ {
+ super( name );
+ setEnabled( true );
+ }
+
+ public void actionPerformed( ActionEvent event )
+ {
+ // TODO: create a dialog that collects the host name and the
base url
+ // and use this to create a new host entry then lauch the host
edit
+ // dialog box. The following is just a placeholder that does
nothing
+ // useful.
+
+ String name = JOptionPane.showInputDialog( m_parent, "Host
name:" );
+ if( null == name )
+ {
+ return;
+ }
+ try
+ {
+ JDialog dialog = new JDialog( m_parent, true );
+ dialog.setTitle( "Resource Host: " + name );
+ JPanel panel = new HostPanel( dialog, name );
+ dialog.setContentPane( panel );
+ Dimension size = new Dimension( 400, 360 );
+ dialog.setSize( size );
+ dialog.setLocationRelativeTo( (Component) event.getSource()
);
+ dialog.setResizable( true );
+ dialog.setVisible( true );
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "Unexpected error while attempting to construct host
dialog."
+ + "\nCODEBASE: "
+ +
ResourcePanel.class.getProtectionDomain().getCodeSource().getLocation().toString();
+ String message = ExceptionHelper.packException( error, e,
true );
+ System.out.println( message );
+ }
+ }
+ }
+
+ private class EditAction extends AbstractAction
+ {
+ public EditAction( String name )
+ {
+ super( name );
+ setEnabled( false );
+ }
+
+ public void actionPerformed( ActionEvent event )
+ {
+ try
+ {
+ JDialog dialog = new JDialog( m_parent, true );
+ dialog.setTitle( "Resource Host: " + m_hostName );
+ JPanel panel = new HostPanel( dialog, m_hostName );
+ dialog.setContentPane( panel );
+ Dimension size = new Dimension( 400, 360 );
+ dialog.setSize( size );
+ dialog.setLocationRelativeTo( (Component) event.getSource()
);
+ dialog.setResizable( true );
+ dialog.setVisible( true );
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "Unexpected error while attempting to construct host
dialog."
+ + "\nCODEBASE: "
+ +
ResourcePanel.class.getProtectionDomain().getCodeSource().getLocation().toString();
+ String message = ExceptionHelper.packException( error, e,
true );
+ System.out.println( message );
+ }
+ }
+ }
+
+ private class DeleteAction extends AbstractAction
+ {
+ public DeleteAction( String name )
+ {
+ super( name );
+ setEnabled( false );
+ }
+
+ public void actionPerformed( ActionEvent event )
+ {
+ if( null == m_hostName )
+ {
+ return;
+ }
+ Preferences hosts = Preferences.userNodeForPackage(
ResourceHost.class );
+ Preferences target = hosts.node( m_hostName );
+ try
+ {
+ target.removeNode();
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "Unexpected error while attempting to delete a host
preferences node."
+ + "\nCODEBASE: "
+ +
ResourcePanel.class.getProtectionDomain().getCodeSource().getLocation().toString();
+ String message = ExceptionHelper.packException( error, e,
true );
+ System.out.println( message );
+ }
+ }
+ }
+
+ public void valueChanged( ListSelectionEvent event )
+ {
+ if( !event.getValueIsAdjusting() )
+ {
+ ListSelectionModel model = m_table.getSelectionModel();
+ synchronized( model )
+ {
+ int n = model.getMinSelectionIndex();
+ if( ( n == model.getMaxSelectionIndex() ) && ( n > -1 ) )
+ {
+ m_hostName = (String) m_table.getValueAt( n, 1 );
+ m_edit.setEnabled( true );
+ m_delete.setEnabled( true );
+ }
+ else
+ {
+ m_hostName = null;
+ m_edit.setEnabled( false );
+ m_delete.setEnabled( false );
+ }
+ }
+ }
+ }
+}

Added:
development/main/transit/core/handler/src/main/net/dpml/transit/prefs/TransitDialog.java
==============================================================================
--- (empty file)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/prefs/TransitDialog.java
Wed May 4 14:32:06 2005
@@ -0,0 +1,267 @@
+/*
+ * 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.prefs;
+
+import java.net.URL;
+
+import java.awt.Color;
+import java.awt.FlowLayout;
+import java.awt.Frame;
+import java.awt.Dimension;
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.Toolkit;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.ActionListener;
+import java.awt.Font;
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+
+import java.util.List;
+import java.util.LinkedList;
+import java.util.Map;
+
+import java.util.prefs.Preferences;
+
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.UIManager;
+import javax.swing.border.EmptyBorder;
+import javax.swing.AbstractAction;
+import javax.swing.JDialog;
+import javax.swing.JButton;
+import javax.swing.Action;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTabbedPane;
+import javax.swing.BoxLayout;
+import javax.swing.Box;
+import javax.swing.ImageIcon;
+import javax.swing.SwingUtilities;
+
+import net.dpml.transit.Transit;
+
+/**
+ */
+public class TransitDialog extends JDialog
+{
+ /**
+ * The DPML icon.
+ */
+ private static String DPML_ICON_FILENAME =
"net/dpml/transit/images/dpml.gif";
+
+ /**
+ * The default dialog width.
+ */
+ private static final int DEFAULT_DIALOG_WIDTH = 400;
+
+ /**
+ * The default dialog height.
+ */
+ private static final int DEFAULT_DIALOG_HEIGHT = 550;
+
+ /**
+ * Empty boarder offset.
+ */
+ private static final int OFFSET = 10;
+
+ /**
+ * Empty boarder offset.
+ */
+ private static final int LEAD = 20;
+
+ /**
+ * Null offset
+ */
+ private static final int ZERO = 0;
+
+ private List m_listeners = new LinkedList();
+
+ public TransitDialog() throws Exception
+ {
+ super();
+
+ String classname = UIManager.getSystemLookAndFeelClassName();
+ UIManager.setLookAndFeel( classname );
+
+ setTitle( "DPML Transit" );
+ Dimension size = new Dimension( DEFAULT_DIALOG_WIDTH,
DEFAULT_DIALOG_HEIGHT );
+ setSize( size );
+
+ JLabel label =
+ IconHelper.createImageIconJLabel(
+ Transit.class.getClassLoader(), DPML_ICON_FILENAME, "", "DPML
Transit" );
+ label.setBorder( new EmptyBorder( 5, 0, 0, 0 ) );
+
+ JTabbedPane tabbedPane = new JTabbedPane();
+ tabbedPane.setBorder( new EmptyBorder( 0, OFFSET, OFFSET, OFFSET ) );
+
+ //
+ // add the individual application control panels as tabbed panes
+ //
+
+ JPanel panel = new JPanel();
+
+ ResourcePanel transitPanel = new ResourcePanel( this );
+ JPanel transitTab = createNamedPanel( "Transit Preferences" ,
transitPanel );
+ tabbedPane.addTab( "Resources", transitPanel );
+ tabbedPane.addTab( "Logging", new JPanel() );
+ tabbedPane.addTab( "Properties", new JPanel() );
+
+ //
+ // add the Close button
+ //
+
+ ButtonPanel buttons = new ButtonPanel();
+ buttons.setBorder( new EmptyBorder( 0, 7, 7, 7 ) );
+
+ //
+ // package
+ //
+
+ JPanel holder = new JPanel( new BorderLayout() );
+ holder.add( label, BorderLayout.NORTH );
+ holder.add( tabbedPane, BorderLayout.CENTER );
+ holder.add( buttons, BorderLayout.SOUTH );
+
+ setContentPane( holder );
+ setSize( size );
+ getRootPane().setDefaultButton( buttons.getDefaultButton() );
+
+ addWindowListener(
+ new WindowAdapter()
+ {
+ public void windowClosing(WindowEvent e)
+ {
+ System.exit(0);
+ }
+ }
+ );
+
+ setLocation( 300, 200 );
+ setVisible(true);
+ }
+
+
+ private static class ButtonPanel extends Box
+ {
+ private JButton m_close;
+
+ ButtonPanel()
+ {
+ super( BoxLayout.Y_AXIS );
+
+ m_close = new JButton( );
+ Action closeAction = new CancelAction( "Close" );
+ m_close.setAction( closeAction );
+ JPanel buttonPanel = new JPanel( new FlowLayout(
FlowLayout.RIGHT ) );
+ buttonPanel.add( m_close );
+ add( buttonPanel );
+ }
+
+ JButton getDefaultButton()
+ {
+ return m_close;
+ }
+ }
+
+ /**
+ * Creation of a panel containing a section in which a name banner is
presented.
+ * @param name the name to assign
+ * @param view the properties content view
+ * @return the panel containing a name header and property content view
+ */
+ private static JPanel createNamedPanel( final String name, Component
view )
+ {
+ JPanel panel = createNamedPanel( name );
+ JPanel holder = new JPanel( new BorderLayout() );
+ holder.add( view, BorderLayout.CENTER );
+ panel.add( holder );
+ return panel;
+ }
+
+ /**
+ * Create the panel holding a name.
+ * @param name the name to assign
+ * @return the panel containing the name as a label
+ */
+ private static JPanel createNamedPanel( final String name )
+ {
+ JPanel panel = new JPanel();
+ panel.setLayout( new BorderLayout() );
+
+ //
+ // Create the header holding the panel name
+ //
+
+ JLabel label = new JLabel( name );
+ label.setBackground( Color.white );
+ label.setBorder( new EmptyBorder( 5, OFFSET, 5, OFFSET ) );
+ JPanel labelHolder = new JPanel( new FlowLayout( FlowLayout.LEFT ) );
+ labelHolder.add( label );
+ labelHolder.setBackground( Color.white );
+ panel.add( labelHolder, BorderLayout.NORTH );
+
+ return panel;
+ }
+
+ private static class CancelAction extends AbstractAction
+ {
+ public CancelAction( String label )
+ {
+ super( label );
+ }
+
+ /**
+ * Called when the cancel button is trigged.
+ * @param event the action event
+ */
+ public void actionPerformed( ActionEvent event )
+ {
+ System.exit(0);
+ }
+ }
+
+ public static void main( String[] args ) throws Exception
+ {
+ SwingUtilities.invokeLater(
+ new Runnable() {
+ public void run()
+ {
+ setup();
+ }
+ } );
+ }
+
+ private static void setup()
+ {
+ try
+ {
+ new TransitDialog();
+ }
+ catch( Exception e )
+ {
+ e.printStackTrace();
+ }
+ }
+}

Added:
development/main/transit/core/handler/src/main/net/dpml/transit/prefs/package.html
==============================================================================
--- (empty file)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/prefs/package.html
Wed May 4 14:32:06 2005
@@ -0,0 +1,8 @@
+
+<body>
+<p>
+The prefs package contains a set of classes dealing with interactive
+management of Transit cache and host preferences.
+</p>
+</body>
+

Modified:
development/main/transit/core/handler/src/main/net/dpml/transit/util/Util.java
==============================================================================
---
development/main/transit/core/handler/src/main/net/dpml/transit/util/Util.java
(original)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/util/Util.java
Wed May 4 14:32:06 2005
@@ -46,7 +46,7 @@
* @return the resolved properties
* @exception IOException if an io error occurs
*/
- static public Properties readProps( URL propsUrl )
+ public static Properties readProps( URL propsUrl )
throws IOException
{
InputStream stream = propsUrl.openStream();
@@ -77,7 +77,7 @@
* @param value the string to parse for tokens
* @return the resolved string
*/
- static public String resolveProperty( Properties props, String value )
+ public static String resolveProperty( Properties props, String value )
{
value = PropertyResolver.resolve( props, value );
return value;
@@ -90,7 +90,7 @@
* @param def the default value
* @return the resolve value
*/
- static public String getProperty( Properties props, String key, String
def )
+ public static String getProperty( Properties props, String key, String
def )
{
String value = props.getProperty( key, def );
if( value == null )
@@ -111,7 +111,7 @@
* @return the lines
* @exception IOException if a read error occurs
*/
- static public String[] readListFile( URL listFile )
+ public static String[] readListFile( URL listFile )
throws IOException
{
ArrayList list = new ArrayList();

Modified:
development/main/transit/core/plugin/src/main/net/dpml/transit/control/CommandHandler.java
==============================================================================
---
development/main/transit/core/plugin/src/main/net/dpml/transit/control/CommandHandler.java
(original)
+++
development/main/transit/core/plugin/src/main/net/dpml/transit/control/CommandHandler.java
Wed May 4 14:32:06 2005
@@ -36,6 +36,7 @@
import net.dpml.transit.repository.Repository;
import net.dpml.transit.repository.RepositoryException;
import net.dpml.transit.artifact.Handler;
+import net.dpml.transit.prefs.TransitDialog;
import net.dpml.transit.util.Dictionary;

import net.dpml.exception.ExceptionHelper;
@@ -165,17 +166,9 @@
String target = line.getOptionValue( "load" );
m_payload = getLoadArguments( target );
}
- else if( line.hasOption( "Xserver" ) )
+ else if( line.hasOption( "manager" ) )
{
- m_command = "server";
- }
- else if( false == line.hasOption( "Xversion" ) )
- {
- Boolean server = (Boolean) map.get( "urn:transit.server" );
- if( !server.booleanValue() )
- {
- m_command = "help";
- }
+ m_command = "manager";
}
}

@@ -217,6 +210,22 @@
{
handleHelpMessage();
}
+ else if( "manager".equals( m_command ) )
+ {
+ handleManager();
+ }
+ }
+
+ private void handleManager()
+ {
+ try
+ {
+ TransitDialog.main( new String[0] );
+ }
+ catch( Throwable e )
+ {
+ e.printStackTrace();
+ }
}

/**
@@ -421,7 +430,6 @@
// actions
//

-
option = new Option( "Xhelp", REZ.getString( "cli-help-description"
) );
options.addOption( option );

@@ -441,7 +449,16 @@
option = OptionBuilder.create( "load" );
group.addOption( option );

+ option = new Option( "manager", REZ.getString(
"cli-manager-description" ) );
+ group.addOption( option );
+
options.addOptionGroup( group );
+
+ //
+ // manager
+ //
+
+
return options;
}


Modified:
development/main/transit/core/plugin/src/main/net/dpml/transit/control/Resources.properties
==============================================================================
---
development/main/transit/core/plugin/src/main/net/dpml/transit/control/Resources.properties
(original)
+++
development/main/transit/core/plugin/src/main/net/dpml/transit/control/Resources.properties
Wed May 4 14:32:06 2005
@@ -12,6 +12,7 @@
cli-version-description=Print version information.
cli-load-description=A uri of a single plugin artifact to be executed by the
controller.
cli-get-description=A comma separated sequence of artifact uris to load into
the local cache.
+cli-manager-description=Launch the Transit Control Panel

cli-server-description=Run the controller as a server (default)
cli-execute-description=On completion of deployment initiate a shutdown.

Modified: development/main/transit/standard.xml
==============================================================================
--- development/main/transit/standard.xml (original)
+++ development/main/transit/standard.xml Wed May 4 14:32:06 2005
@@ -226,6 +226,18 @@
<copy toDir="${target.build.main.dir}" filtering="on"
failonerror="false">
<fileset dir="${etc.main}">
<include name="**/*"/>
+ <exclude name="**/*.jpg"/>
+ <exclude name="**/*.jpeg"/>
+ <exclude name="**/*.png"/>
+ <exclude name="**/*.gif"/>
+ </fileset>
+ </copy>
+ <copy toDir="${target.build.main.dir}" filtering="off"
failonerror="false">
+ <fileset dir="${etc.main}">
+ <include name="**/*.jpg"/>
+ <include name="**/*.jpeg"/>
+ <include name="**/*.png"/>
+ <include name="**/*.gif"/>
</fileset>
</copy>
</target>
@@ -275,6 +287,18 @@
<copy toDir="${target.build.main.dir}" filtering="on"
failonerror="false">
<fileset dir="${src.main.dir}">
<include name="**/*"/>
+ <exclude name="**/*.gif"/>
+ <exclude name="**/*.png"/>
+ <exclude name="**/*.jpeg"/>
+ <exclude name="**/*.jpg"/>
+ </fileset>
+ </copy>
+ <copy toDir="${target.build.main.dir}" filtering="off"
failonerror="false">
+ <fileset dir="${src.main.dir}">
+ <include name="**/*.gif"/>
+ <include name="**/*.png"/>
+ <include name="**/*.jpeg"/>
+ <include name="**/*.jpg"/>
</fileset>
</copy>
</target>
@@ -289,6 +313,18 @@
<copy toDir="${target.build.test.dir}" filtering="on"
failonerror="false">
<fileset dir="${src.test.dir}">
<include name="**/*"/>
+ <exclude name="**/*.gif"/>
+ <exclude name="**/*.png"/>
+ <exclude name="**/*.jpeg"/>
+ <exclude name="**/*.jpg"/>
+ </fileset>
+ </copy>
+ <copy toDir="${target.build.test.dir}" filtering="off"
failonerror="false">
+ <fileset dir="${src.test.dir}">
+ <include name="**/*.gif"/>
+ <include name="**/*.png"/>
+ <include name="**/*.jpeg"/>
+ <include name="**/*.jpg"/>
</fileset>
</copy>
</target>



  • svn commit: r2459 - in development/main/transit: . core/handler/etc/setup/authority/hosts core/handler/src/main/net/dpml/transit core/handler/src/main/net/dpml/transit/cache core/handler/src/main/net/dpml/transit/event core/handler/src/main/net/dpml/transit/host core/handler/src/main/net/dpml/transit/images core/handler/src/main/net/dpml/transit/prefs core/handler/src/main/net/dpml/transit/util core/plugin/src/main/net/dpml/transit/control, mcconnell, 05/04/2005

Archive powered by MHonArc 2.6.24.

Top of Page