Skip to Content.
Sympa Menu

notify-dpml - svn commit: r2129 - in development/main: metro/composition/impl/src/main/net/dpml/composition/model/impl metro/composition/impl/src/test/net/dpml/composition/model/impl metro/composition/test/etc/test metro/composition/test/src/test/net/dpml/composition/model/impl/test metro/composition/test/src/test/net/dpml/composition/util transit/core/handler/src/main/net/dpml/transit transit/core/handler/src/main/net/dpml/transit/artifact transit/core/handler/src/test/net/dpml/transit/artifact

notify-dpml AT lists.ibiblio.org

Subject: DPML Notify

List archive

Chronological Thread  
  • From: niclas AT hedhman.org
  • To: notify-dpml AT lists.ibiblio.org
  • Subject: svn commit: r2129 - in development/main: metro/composition/impl/src/main/net/dpml/composition/model/impl metro/composition/impl/src/test/net/dpml/composition/model/impl metro/composition/test/etc/test metro/composition/test/src/test/net/dpml/composition/model/impl/test metro/composition/test/src/test/net/dpml/composition/util transit/core/handler/src/main/net/dpml/transit transit/core/handler/src/main/net/dpml/transit/artifact transit/core/handler/src/test/net/dpml/transit/artifact
  • Date: Thu, 24 Mar 2005 18:03:31 -0500

Author: niclas AT hedhman.org
Date: Thu Mar 24 18:03:30 2005
New Revision: 2129

Added:

development/main/transit/core/handler/src/main/net/dpml/transit/artifact/ArtifactAlreadyExistsException.java
(contents, props changed)

development/main/transit/core/handler/src/main/net/dpml/transit/artifact/ConnectionCache.java
(contents, props changed)

development/main/transit/core/handler/src/main/net/dpml/transit/artifact/EclipseResolver.java
(contents, props changed)

development/main/transit/core/handler/src/main/net/dpml/transit/artifact/StreamUtils.java
(contents, props changed)

development/main/transit/core/handler/src/main/net/dpml/transit/artifact/ZipCache.java
(contents, props changed)
Removed:

development/main/transit/core/handler/src/main/net/dpml/transit/artifact/Policy.java
Modified:

development/main/metro/composition/impl/src/main/net/dpml/composition/model/impl/DefaultClassLoaderModel.java

development/main/metro/composition/impl/src/test/net/dpml/composition/model/impl/CommissionerTestCase.java
development/main/metro/composition/test/etc/test/ConfigurableB.xml
development/main/metro/composition/test/etc/test/ConfigurableB.xschema
development/main/metro/composition/test/etc/test/context.xml
development/main/metro/composition/test/etc/test/schemavalidation.xml
development/main/metro/composition/test/etc/test/targets.xml

development/main/metro/composition/test/src/test/net/dpml/composition/model/impl/test/TargetsTestCase.java

development/main/metro/composition/test/src/test/net/dpml/composition/util/SchemaValidationTestCase.java
development/main/transit/core/handler/src/main/net/dpml/transit/Main.java

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

development/main/transit/core/handler/src/main/net/dpml/transit/artifact/Artifact.java

development/main/transit/core/handler/src/main/net/dpml/transit/artifact/ArtifactURLConnection.java

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

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

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

development/main/transit/core/handler/src/main/net/dpml/transit/artifact/NetworkLoader.java

development/main/transit/core/handler/src/main/net/dpml/transit/artifact/RemoteCacheHandler.java

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

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

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

development/main/transit/core/handler/src/main/net/dpml/transit/artifact/XMLHostsBuilder.java

development/main/transit/core/handler/src/test/net/dpml/transit/artifact/OfflineTestCase.java
Log:
o Large refactoring of Transit.
o Support for openConnection().getOutputStream() in Transit, which will write
to the cache, provided it does not exist already.
o Source code formatting.

Modified:
development/main/metro/composition/impl/src/main/net/dpml/composition/model/impl/DefaultClassLoaderModel.java
==============================================================================
---
development/main/metro/composition/impl/src/main/net/dpml/composition/model/impl/DefaultClassLoaderModel.java
(original)
+++
development/main/metro/composition/impl/src/main/net/dpml/composition/model/impl/DefaultClassLoaderModel.java
Thu Mar 24 18:03:30 2005
@@ -151,10 +151,10 @@

m_urls = buildQualifiedClassPath();

- m_classLoader =
- new URLClassLoader(
- m_urls, context.getClassLoader(),
- new ArtifactURLStreamHandlerFactory() );
+ ClassLoader classloader = context.getClassLoader();
+ ArtifactURLStreamHandlerFactory factory =
+ new ArtifactURLStreamHandlerFactory();
+ m_classLoader = new URLClassLoader( m_urls, classloader, factory
);

//m_classLoader =
// new StandardClassLoader(

Modified:
development/main/metro/composition/impl/src/test/net/dpml/composition/model/impl/CommissionerTestCase.java
==============================================================================
---
development/main/metro/composition/impl/src/test/net/dpml/composition/model/impl/CommissionerTestCase.java
(original)
+++
development/main/metro/composition/impl/src/test/net/dpml/composition/model/impl/CommissionerTestCase.java
Thu Mar 24 18:03:30 2005
@@ -1,23 +1,23 @@
-/*
+/*
* 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
- *
+ * 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.composition.model.impl;
-
+
import net.dpml.composition.model.CommissioningException;
import net.dpml.composition.model.FatalCommissioningException;
import net.dpml.composition.model.DeploymentModel;
@@ -30,7 +30,7 @@
public class CommissionerTestCase extends TestCase
{
private Commissioner m_commissioner;
-
+
public void setUp()
{
ConsoleLogger logger = new ConsoleLogger( ConsoleLogger.LEVEL_INFO );
@@ -43,12 +43,12 @@
m_commissioner.dispose();
m_commissioner = null;
}
-
+
public void testNormalDeploy()
throws Exception
{
Commissionable d = new SimpleCommissionable();
- DeploymentModel model = new SimpleDeploymentModel( d, 100, false );
+ DeploymentModel model = new SimpleDeploymentModel( d, 1000, false );
m_commissioner.commission( model );
}

@@ -58,87 +58,87 @@
try
{
Commissionable d = new InterruptableCommissionable();
- DeploymentModel model = new SimpleDeploymentModel( d, 100, false
);
+ DeploymentModel model = new SimpleDeploymentModel( d, 1000,
false );
m_commissioner.commission( model );

fail( "The Deployment didn't fail with a
CommissioningException." );
- }
+ }
catch( FatalCommissioningException e )
{
fail( "The Exception thrown was a FatalCommissioningException."
);
- }
+ }
catch( CommissioningException e )
{
// testcase success
}
}
-
+
public void testUninterruptableDeploy()
throws Exception
{
UninterruptableCommissionable d = new
UninterruptableCommissionable();
try
{
- DeploymentModel model = new SimpleDeploymentModel( d, 100, false
);
+ DeploymentModel model = new SimpleDeploymentModel( d, 1000,
false );
m_commissioner.commission( model );
fail( "The Deployment didn't fail with a
FatalDeploymentException." );
- }
+ }
catch( FatalCommissioningException e )
{
// testcase success
- }
+ }
catch( CommissioningException e )
{
fail( "The Exception thrown was a CommissioningException, when a
FatalCommissioningException was expected." );
- }
+ }
finally
{
d.stop();
}
}
-
+
public void testCustomExceptionDeploy()
throws Exception
{
try
{
Commissionable d = new CustomExceptionDeployable();
- DeploymentModel model = new SimpleDeploymentModel( d, 100, false
);
+ DeploymentModel model = new SimpleDeploymentModel( d, 1000,
false );
m_commissioner.commission( model );
fail( "The Deployment didn't fail with a DeploymentException." );
- }
+ }
catch( CustomException e )
{
// success
- }
+ }
catch( FatalCommissioningException e )
{
fail( "The Exception thrown was a FatalCommissioningException."
);
- }
+ }
catch( CommissioningException e )
{
fail( "The Exception thrown was a CommissioningException." );
}
}
-
+
public void testCustomErrorDeploy()
throws Exception
{
try
{
Commissionable d = new CustomErrorDeployable();
- DeploymentModel model = new SimpleDeploymentModel( d, 100, false
);
+ DeploymentModel model = new SimpleDeploymentModel( d, 1000,
false );
m_commissioner.commission( model );
fail( "The Deployment didn't fail with a DeploymentException." );
- }
+ }
catch( CustomError e )
{
// success
- }
+ }
catch( FatalCommissioningException e )
{
fail( "The Exception thrown was a FatalCommissioningException."
);
- }
+ }
catch( CommissioningException e )
{
fail( "The Exception thrown was a CommissioningException." );

Modified: development/main/metro/composition/test/etc/test/ConfigurableB.xml
==============================================================================
--- development/main/metro/composition/test/etc/test/ConfigurableB.xml
(original)
+++ development/main/metro/composition/test/etc/test/ConfigurableB.xml Thu
Mar 24 18:03:30 2005
@@ -1,3 +1,3 @@
<configuration attr1="foo">
- <child1/>
+ <child1/>
</configuration>

Modified:
development/main/metro/composition/test/etc/test/ConfigurableB.xschema
==============================================================================
--- development/main/metro/composition/test/etc/test/ConfigurableB.xschema
(original)
+++ development/main/metro/composition/test/etc/test/ConfigurableB.xschema
Thu Mar 24 18:03:30 2005
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema";>
- <xs:element name="configuration">
- <xs:complexType>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema";>
+ <xs:element name="configuration">
+ <xs:complexType>
<xs:sequence>
<xs:element name="child1" type="xs:string"/>
</xs:sequence>
<xs:attribute name="attr1" type="xs:string"/>
</xs:complexType>
- </xs:element>
- </xs:schema>
+ </xs:element>
+</xs:schema>

Modified: development/main/metro/composition/test/etc/test/context.xml
==============================================================================
--- development/main/metro/composition/test/etc/test/context.xml
(original)
+++ development/main/metro/composition/test/etc/test/context.xml Thu
Mar 24 18:03:30 2005
@@ -1,29 +1,29 @@


- <container name="test">
+<container name="test">

- <classloader>
- <classpath>
- <artifact>@AVALON-API-SPEC@</artifact>
- <artifact>@TEST-A-SPEC@</artifact>
- </classpath>
- </classloader>
+ <classloader>
+ <classpath>
+ <artifact>@AVALON-API-SPEC@</artifact>
+ <artifact>@TEST-A-SPEC@</artifact>
+ </classpath>
+ </classloader>

- <component name="test-a" class="net.dpml.test.testa.TestA">
- <context class="net.dpml.test.testa.DefaultFacade">
- <entry key="home">
- <constructor class="java.io.File">
- <param class="java.io.File">${urn:avalon:home}</param>
- <param>xxx</param>
- </constructor>
- </entry>
- <entry key="time">
- <constructor class="java.util.Date"/>
- </entry>
- <entry key="path">
- <import key="urn:avalon:partition"/>
- </entry>
- </context>
- </component>
+ <component name="test-a" class="net.dpml.test.testa.TestA">
+ <context class="net.dpml.test.testa.DefaultFacade">
+ <entry key="home">
+ <constructor class="java.io.File">
+ <param class="java.io.File">${urn:avalon:home}</param>
+ <param>xxx</param>
+ </constructor>
+ </entry>
+ <entry key="time">
+ <constructor class="java.util.Date"/>
+ </entry>
+ <entry key="path">
+ <import key="urn:avalon:partition"/>
+ </entry>
+ </context>
+ </component>

- </container>
+</container>

Modified:
development/main/metro/composition/test/etc/test/schemavalidation.xml
==============================================================================
--- development/main/metro/composition/test/etc/test/schemavalidation.xml
(original)
+++ development/main/metro/composition/test/etc/test/schemavalidation.xml
Thu Mar 24 18:03:30 2005
@@ -1,16 +1,16 @@
<container name="test">
- <classloader>
- <classpath>
- <artifact>@AVALON-API-SPEC@</artifact>
- <artifact>@AVALON-IMPL-SPEC@</artifact>
- <artifact>@TEST-SCHEMA-SPEC@</artifact>
- </classpath>
- </classloader>
- <container name="sub">
- <component name="ConfigB"
class="net.dpml.test.testschema.ConfigurableB">
- <configuration attr1="foo">
- <child1/>
- </configuration>
- </component>
- </container>
+ <classloader>
+ <classpath>
+ <artifact>@AVALON-API-SPEC@</artifact>
+ <artifact>@AVALON-IMPL-SPEC@</artifact>
+ <artifact>@TEST-SCHEMA-SPEC@</artifact>
+ </classpath>
+ </classloader>
+ <container name="sub">
+ <component name="ConfigB" class="net.dpml.test.testschema.ConfigurableB">
+ <configuration attr1="foo">
+ <child1/>
+ </configuration>
+ </component>
+ </container>
</container>
\ No newline at end of file

Modified: development/main/metro/composition/test/etc/test/targets.xml
==============================================================================
--- development/main/metro/composition/test/etc/test/targets.xml
(original)
+++ development/main/metro/composition/test/etc/test/targets.xml Thu
Mar 24 18:03:30 2005
@@ -1,5 +1,5 @@

- <container name="test">
+<container name="test">

<classloader>
<classpath>
@@ -9,19 +9,13 @@
</classpath>
</classloader>

- <component
- class="net.dpml.test.testa.ConfigurableComponent"
- name="aaa"/>
-
- <component
- class="net.dpml.test.testa.ConfigurableComponent"
- name="bbb"/>
+ <component name="aaa" class="net.dpml.test.testa.ConfigurableComponent" />
+
+ <component name="bbb" class="net.dpml.test.testa.ConfigurableComponent" />

<container name="ccc">
<container name="sss">
- <component
- class="net.dpml.test.testa.ConfigurableComponent"
- name="xxx"/>
+ <component name="xxx"
class="net.dpml.test.testa.ConfigurableComponent" />
</container>
</container>


Modified:
development/main/metro/composition/test/src/test/net/dpml/composition/model/impl/test/TargetsTestCase.java
==============================================================================
---
development/main/metro/composition/test/src/test/net/dpml/composition/model/impl/test/TargetsTestCase.java
(original)
+++
development/main/metro/composition/test/src/test/net/dpml/composition/model/impl/test/TargetsTestCase.java
Thu Mar 24 18:03:30 2005
@@ -1,16 +1,16 @@
-/*
+/*
* Copyright 2004 Apache Software Foundation
* 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
- *
+ * 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.
*/
@@ -33,15 +33,15 @@


public class TargetsTestCase extends CompositionTestCase
-{
+{
//------------------------------------------------------------------
- // static
+ // static
//------------------------------------------------------------------

private static final String PATH = "targets.xml";

//------------------------------------------------------------------
- // state
+ // state
//------------------------------------------------------------------

private ContainmentModel m_model;
@@ -66,7 +66,8 @@
{
try
{
- File source =
+
+ File source =
new File( WORK, "targets-config.xml" );
TargetDirective[] targets = loadTargets( source ).getTargets();
for( int i=0; i<targets.length; i++ )
@@ -75,8 +76,7 @@
final String path = target.getPath();
DeploymentModel model = m_model.getModel( path );

- CategoriesDirective categories =
- target.getCategoriesDirective();
+ CategoriesDirective categories =
target.getCategoriesDirective();
if( null != categories )
{
model.setCategories( categories );
@@ -87,11 +87,11 @@
ComponentModel deployment = (ComponentModel) model;
Configuration config = target.getConfiguration();
if( null != config )
- {
+ {
deployment.setConfiguration( config );
}
//getLogger().debug( "model: " + deployment );
- //getLogger().debug(
+ //getLogger().debug(
// ConfigurationUtil.list(
deployment.getConfiguration() ) );
}
}
@@ -111,6 +111,7 @@
DefaultConfigurationBuilder builder = new
DefaultConfigurationBuilder();
Configuration config = builder.buildFromFile( file );
XMLTargetsCreator creator = new XMLTargetsCreator();
- return creator.createTargets( config );
+ Targets result = creator.createTargets( config );
+ return result;
}
}

Modified:
development/main/metro/composition/test/src/test/net/dpml/composition/util/SchemaValidationTestCase.java
==============================================================================
---
development/main/metro/composition/test/src/test/net/dpml/composition/util/SchemaValidationTestCase.java
(original)
+++
development/main/metro/composition/test/src/test/net/dpml/composition/util/SchemaValidationTestCase.java
Thu Mar 24 18:03:30 2005
@@ -1,17 +1,17 @@
-/*
+/*
* 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
- *
+ * 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.
*/
@@ -57,7 +57,7 @@
private Hashtable m_errors;

/**
- *
+ *
*/
public TestHandler()
{
@@ -66,7 +66,7 @@
}

/**
- *
+ *
* @see org.xml.sax.ErrorHandler#error(org.xml.sax.SAXParseException)
*/
public void error( SAXParseException e ) throws SAXException
@@ -189,7 +189,7 @@
}
catch ( ModelException e )
{
- fail( "should bo ok" );
+ fail( "should be ok" );
e.printStackTrace();
}
}

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
Thu Mar 24 18:03:30 2005
@@ -31,8 +31,11 @@
import net.dpml.transit.adapter.CacheMonitorAdapter;
import net.dpml.transit.adapter.NetworkMonitorAdapter;
import net.dpml.transit.adapter.ConsoleAdapter;
+
import net.dpml.transit.artifact.Artifact;
import net.dpml.transit.artifact.ResourceManager;
+import net.dpml.transit.artifact.SecuredTransitContext;
+
import net.dpml.transit.monitors.Monitor;
import net.dpml.transit.monitors.RepositoryMonitor;
import net.dpml.transit.monitors.CacheMonitor;
@@ -40,6 +43,7 @@
import net.dpml.transit.monitors.SystemMonitor;
import net.dpml.transit.monitors.ConsoleMonitor;
import net.dpml.transit.monitors.SystemMonitor;
+
import net.dpml.transit.util.Dictionary;

/**
@@ -69,12 +73,12 @@

/**
* The main method is the static commandline entry point for transit
enabled
- * applications. The implementation requires a cli argument
"-Xbootstrap=[artifact]"
- * referencing an artifact uri of a transit plugin to be deployed as the
target
- * application. On completion of the establishment of a series of
console based
- * monitors, the implementation passes command line arguments to the
application
- * plugin using the transit application deployment service. Debug level
trace
- * messages related to transit initialization can be enabled by including
the
+ * applications. The implementation requires a cli argument
"-Xbootstrap=[artifact]"
+ * referencing an artifact uri of a transit plugin to be deployed as the
target
+ * application. On completion of the establishment of a series of
console based
+ * monitors, the implementation passes command line arguments to the
application
+ * plugin using the transit application deployment service. Debug level
trace
+ * messages related to transit initialization can be enabled by including
the
* "-Xdebug" commandline option.
*
* @param args command line argument to be passed to the application
@@ -87,7 +91,7 @@
//
// Setup transit protocol handler
//
-
+
File propsFile = new File( Transit.DPML_PREFS,
"transit/system.properties" );
if( propsFile.exists() )
{
@@ -100,7 +104,7 @@
catch( Exception e )
{
System.out.println( "Can't read: " + propsFile );
- }
+ }
finally
{
fis.close();
@@ -148,7 +152,9 @@
// setup transit
//

- Transit transit = Transit.getInstance( server, monitor );
+ Transit transit = Transit.getInstance( monitor );
+ SecuredTransitContext context = transit.getTransitContext();
+ context.setServer( server );

Adapter adapter = new ConsoleAdapter( debug );
RepositoryMonitor repoMonitor = new RepositoryMonitorAdapter(
adapter );
@@ -172,7 +178,7 @@

if( monitor.isTraceEnabled() )
{
- final String message =
+ final String message =
"using -Xbootstrap argument: ["
+ path
+ "]";
@@ -189,8 +195,8 @@
{
if( monitor.isTraceEnabled() )
{
- final String message =
- "using system property "
+ final String message =
+ "using system property "
+ BOOTSTRAP_URI_KEY
+ " with value: ["
+ path
@@ -222,7 +228,7 @@

adapter.debug( "Starting transit." );
adapter.debug( uri.toString() );
-
+
transit.start( uri, params );
}


Modified:
development/main/transit/core/handler/src/main/net/dpml/transit/Transit.java
==============================================================================
---
development/main/transit/core/handler/src/main/net/dpml/transit/Transit.java
(original)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/Transit.java
Thu Mar 24 18:03:30 2005
@@ -95,7 +95,7 @@
private RepositoryMonitorRouter m_repositoryMonitor;

/**
- * Singleton cahce monitor router.
+ * Singleton cache monitor router.
*/
private CacheMonitorRouter m_cacheMonitor;

@@ -110,6 +110,8 @@
*/
private PrintWriter m_logWriter;

+ private SecuredTransitContext m_context;
+
/**
* The DPML home directory established via assesment of the the
${dpml.home}
* system property and the DPML_HOME environment variable. If neither are
@@ -161,7 +163,7 @@
public static Transit getInstance()
throws TransitException
{
- return Transit.getInstance( false, new SystemMonitor() );
+ return Transit.getInstance( new SystemMonitor() );
}

/**
@@ -176,21 +178,6 @@
public static Transit getInstance( SystemMonitor monitor )
throws TransitException, NullArgumentException
{
- return Transit.getInstance( false, new SystemMonitor() );
- }
-
- /**
- * Returns the singleton instance of the transit system. If this method
- * has already been invoked the monitor argument will be ignored.
- * @param server the server mode
- * @param monitor the bootstrap monitor
- * @return the singleton transit instance
- * @exception TransitException if an error occurs during establishment
- * @exception NullArgumentException if the monitor argument is null.
- */
- public static Transit getInstance( boolean server, SystemMonitor monitor
)
- throws TransitException, NullArgumentException
- {
if( null == monitor )
{
throw new NullArgumentException( "monitor" );
@@ -199,35 +186,25 @@
{
if( m_INSTANCE == null )
{
- m_INSTANCE = new Transit( server, monitor );
+ m_INSTANCE = new Transit( monitor );
}
return m_INSTANCE;
}
}

- private boolean m_server;
-
- /**
- * Private constructor of a transit instance.
- * @param monitor the bootstrap monitor
- * @exception TransitException if an establishment error occurs
- */
- public Transit( SystemMonitor monitor )
- throws TransitException
+ SecuredTransitContext getTransitContext()
{
- this( false, monitor );
+ return m_context;
}

/**
* Private constructor of a transit instance.
- * @param server the server mode
* @param monitor the bootstrap monitor
* @exception TransitException if an establishment error occurs
*/
- private Transit( boolean server, SystemMonitor monitor )
+ private Transit( SystemMonitor monitor )
throws TransitException
{
- m_server = server;
try
{
if( monitor.isTraceEnabled() )
@@ -235,11 +212,16 @@
monitor.trace( "creating transit instance" );
}

- SecuredTransitContext.create( server, monitor ); // Ensure
secured environment.
+ m_context = SecuredTransitContext.create( monitor ); // Ensure
secured environment.
m_repositoryMonitor = new RepositoryMonitorRouter( monitor );
m_cacheMonitor = new CacheMonitorRouter( monitor );
m_networkMonitor = new NetworkMonitorRouter( monitor );

+ // Setting up a temporary directory for Transit.
+
+ File temp = new File( DPML_DATA, "temp" );
+ temp.mkdirs();
+
// Setting up a permanent output troubleshooting resource
// for Transit.
File logs = new File( DPML_DATA, "logs" );
@@ -307,11 +289,6 @@
public Object start( URI uri, Object[] args )
throws TransitException, URISyntaxException, IOException,
NullArgumentException
{
- if( m_server )
- {
- return null;
- }
-
if( null == uri )
{
throw new NullArgumentException( "uri" );
@@ -512,4 +489,5 @@
return new File( dir, "prefs" );
}
}
+
}

Modified:
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/Artifact.java
==============================================================================
---
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/Artifact.java
(original)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/Artifact.java
Thu Mar 24 18:03:30 2005
@@ -143,10 +143,21 @@
* @return the new artifact
* @exception java.net.URISyntaxException if the supplied set of argument
* is not a valid URI.
+ * @exception NullArgumentException if any of the <code>group</code>,
+ * <code>name</code> or <code>type</code> arguments are
+ * <code>null</code>.
*/
public static Artifact createArtifact( String group, String name, String
version, String type )
- throws URISyntaxException
+ throws URISyntaxException, NullArgumentException
{
+ if( group == null )
+ throw new NullArgumentException( "group" );
+ if( name == null )
+ throw new NullArgumentException( "name" );
+ if( type == null )
+ throw new NullArgumentException( "type" );
+ if( version == null )
+ version = "";
String composite = "artifact:" + type + ":" + group + "/" + name +
"#" + version;
URI uri = new URI( composite );
return new Artifact( uri );

Added:
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/ArtifactAlreadyExistsException.java
==============================================================================
--- (empty file)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/ArtifactAlreadyExistsException.java
Thu Mar 24 18:03:30 2005
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2004-2005 Stephen J. McConnell.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.dpml.transit.artifact;
+
+/**
+ * Exception to indicate that the Artifact already exists in the cache and
+ * can therefor not be written to.
+ *
+ * @author <a href="mailto:dev-dpml AT lists.ibiblio.org";>The Digital Product
Meta Library</a>
+ * @version $Id$
+ */
+public class ArtifactAlreadyExistsException extends ArtifactException
+{
+ //
------------------------------------------------------------------------
+ // state
+ //
------------------------------------------------------------------------
+
+ /**
+ * The artifact that we tried to write to.
+ */
+ private final Artifact m_artifact;
+
+ //
------------------------------------------------------------------------
+ // constructor
+ //
------------------------------------------------------------------------
+
+ /**
+ * Construct a new <code>ArtifactAlreadyExistsException</code> instance.
+ *
+ * @param artifact the subject artifact
+ */
+ public ArtifactAlreadyExistsException( final String message, final
Artifact artifact )
+ {
+ super( message );
+ m_artifact = artifact;
+ }
+
+ /**
+ * Returns the Artifact that were attempted to be written to.
+ * @return the subject artifact
+ */
+ public Artifact getArtifact()
+ {
+ return m_artifact;
+ }
+}
+

Modified:
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/ArtifactURLConnection.java
==============================================================================
---
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/ArtifactURLConnection.java
(original)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/ArtifactURLConnection.java
Thu Mar 24 18:03:30 2005
@@ -17,6 +17,7 @@

package net.dpml.transit.artifact;

+import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
@@ -27,6 +28,8 @@
import java.net.URLConnection;
import java.net.URISyntaxException;

+import net.dpml.transit.Transit;
+
/**
* Artifact URL protocol connection processor.
*/
@@ -52,11 +55,6 @@
private final String m_reference;

/**
- * Cached file.
- */
- private File m_local;
-
- /**
* The connected state.
*/
private boolean m_connected;
@@ -106,47 +104,39 @@
public void connect()
throws IOException
{
- CacheHandler cache = m_context.getCacheHandler();
- if( m_local == null )
- {
- m_local = cache.getResource( m_artifact );
- }
m_connected = true;
}

/**
- * Return an imput stream to the resource.
+ * Return an input stream to the resource.
* @return the input stream
* @exception IOException is an error occurs
*/
public InputStream getInputStream()
throws IOException
{
- if( !m_connected )
- {
- connect();
- }
+ connect();
+ CacheHandler cache = m_context.getCacheHandler();
if( null != m_reference )
{
- URL url = new URL( "jar:" + m_local.toURL().toString() +
m_reference );
- return url.openConnection().getInputStream();
+ return cache.getResource( m_artifact, m_reference );
}
else
{
- return m_local.toURL().openStream();
+ return cache.getResource( m_artifact );
}
}

/**
* Return an output stream to the resource.
* @return the output stream
- * @exception IOException not implemented
- * @exception UnknownServiceException allways thrown
+ * @exception IOException if any I/O problems occur.
*/
public OutputStream getOutputStream()
- throws IOException, UnknownServiceException
+ throws IOException
{
- throw new UnknownServiceException( "Artifacts can not be written
to." );
+ CacheHandler cache = m_context.getCacheHandler();
+ return cache.createOutputStream( m_artifact );
}

/**
@@ -191,10 +181,19 @@
Class c = classes[i];
if( c.equals( File.class ) )
{
- return m_local;
+ InputStream content = getInputStream();
+ LocationResolver resolver = new ClassicResolver();
+ String name = resolver.resolvePath( m_artifact );
+ File tempDir = new File( Transit.DPML_DATA, "temp" );
+ File destDir = new File( tempDir, name );
+ destDir.mkdirs();
+ File tempFile = File.createTempFile( "dpml", ".tmp", destDir
);
+ tempFile.deleteOnExit();
+ FileOutputStream output = new FileOutputStream( tempFile );
+ StreamUtils.copyStream( content, output, true );
+ return tempFile;
}
}
-
return null;
}


Modified:
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/CacheHandler.java
==============================================================================
---
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/CacheHandler.java
(original)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/CacheHandler.java
Thu Mar 24 18:03:30 2005
@@ -19,12 +19,16 @@

package net.dpml.transit.artifact;

-import java.io.File;
+import java.io.InputStream;
import java.io.IOException;
+import java.io.OutputStream;
+
import java.rmi.Remote;
import java.rmi.RemoteException;
+
import java.util.Map;

+import net.dpml.lang.NullArgumentException;

import net.dpml.transit.TransitException;

@@ -60,15 +64,50 @@

/**
* Attempts to download and cache a remote artifact using a set of remote
- * repositories. The operation is not fail fast and so it keeps trying
if
- * the first repository does not have the artifact in question.
+ * repositories.
+ *
+ * @param artifact the artifact to retrieve and cache
+ * @return a file referencing the local resource
+ * @exception IOException if an IO error occurs
+ * @exception TransitException is a transit system error occurs
+ */
+ InputStream getResource( Artifact artifact )
+ throws IOException, TransitException, RemoteException;
+
+ /**
+ * Attempts to download and cache a remote artifact using a set of remote
+ * repositories.
+ * <p>
+ * This method allows an internal reference to be passed to the
+ * cache handler and it is expected to return the InputStream of the
+ * internal item inside Jar/Zip files. If this method is called, the
+ * implementation can assume that the artifact is a Zip file.
+ * </p>
*
* @param artifact the artifact to retrieve and cache
+ * @param internalReference referencing a item within the artifact. This
+ * argument may start with "!" or "!/", which should be ignored.
* @return a file referencing the local resource
* @exception IOException if an IO error occurs
* @exception TransitException is a transit system error occurs
*/
- File getResource( Artifact artifact )
+ InputStream getResource( Artifact artifact, String internalReference )
throws IOException, TransitException, RemoteException;

+ /** Creates an output stream to where the artifact content can be written
+ * to.
+ * <p>
+ * If the artifact already exists, a
<code>ArtifactAlreadyExistsException</code>
+ * will be thrown. If the directory doesn't exists, it will be created.
+ * The CacheHandler is responsible to recognize the completion of the
+ * writes through the <code>close()</code> method in the output stream,
+ * and do any post-processing there.
+ * </p>
+ * @exception NullArgumentException if the artifact argument is null.
+ * @exception ArtifactAlreadyExistsException if the artifact already
exists
+ * in the cache.
+ */
+ OutputStream createOutputStream( Artifact artifact )
+ throws NullArgumentException, ArtifactAlreadyExistsException,
IOException, RemoteException;
+
}

Modified:
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/ClassicResourceHost.java
==============================================================================
---
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/ClassicResourceHost.java
(original)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/ClassicResourceHost.java
Thu Mar 24 18:03:30 2005
@@ -20,7 +20,9 @@
package net.dpml.transit.artifact;

import java.io.File;
+import java.io.InputStream;
import java.io.IOException;
+import java.io.OutputStream;
import java.io.PrintWriter;

import java.net.HttpURLConnection;
@@ -38,6 +40,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.WeakHashMap;
+import java.util.Date;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
@@ -113,14 +116,9 @@
private boolean m_trusted;

/**
- * Timestamp policy.
- */
- private Policy m_policy;
-
- /**
* Connections.
*/
- private WeakHashMap m_connections;
+ private ConnectionCache m_connections;

private LocationResolver m_resolver;

@@ -136,27 +134,30 @@
* @param base the host base url
* @param knownGroups known groups within the host
* @param priority host priority
- * @param downloadPolicy the timestamping policy
* @param enabled the enabled state
* @param trusted the trusted state
* @param username an authentication username
* @param password the authentication password
* @param scheme the authentication scheme
* @param prompt the authentication prompt/realm
+ * @param resolver the LocationResolver to use.
* @exception UnknownHostException if the supplied base url references
an unknown host
*/
public ClassicResourceHost(
- URL base, String[] knownGroups, int priority, Policy downloadPolicy,
- boolean enabled, boolean trusted, String username, String password,
String scheme, String prompt )
+ URL base, String[] knownGroups, int priority, boolean enabled,
+ boolean trusted, String username, String password, String scheme,
+ String prompt, LocationResolver resolver )
throws UnknownHostException
{
- m_resolver = new ClassicResolver();
+ if( resolver != null )
+ m_resolver = resolver;
+ else
+ m_resolver = new ClassicResolver();
m_locks = new HashMap();
- m_connections = new WeakHashMap();
+ m_connections = ConnectionCache.getInstance();
m_baseUrl = base;
m_priority = priority;
m_knownGroups = new HashSet();
- m_policy = downloadPolicy;
m_trusted = trusted;
m_enabled = enabled;

@@ -222,34 +223,33 @@
return m_priority;
}

- /** Downloads the given artifact to the given file.
- *
+ /** 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
+ * group if nonexistent.
+ * </p>
+ * <p>
+ * If the knownOnly argument is true, then only attempt download if the
+ * group is known to exist on this resource host.
+ * </p>
* @param artifact the artifact that is requested to be downloaded.
- * @param destFile The file where to place the downloaded content.
- * @exception IOException if an IO error occurs
+ * @param dest The output stream where to write the downloaded content.
+ * @exception IOException if an IO related error occurs
*/
- public void download( Artifact artifact, File destFile )
+ public Date download( Artifact artifact, OutputStream dest )
throws IOException
{
Object lock = obtainLock( artifact );
synchronized ( lock )
{
- if( destFile.exists() && ( getDownloadPolicy() == Policy.FAST ) )
- {
- return;
- }
-
NetworkLoader loader = new NetworkLoader();
URL url = createRemoteUrl( artifact );

URLConnection connection;
synchronized ( m_connections )
{
- connection = (URLConnection) m_connections.get( artifact );
- // TODO: Investigate if the cache is used properly.
- // Niclas: I suspect that the value is dropped from the
- // WeakHashMap more or less immediately, and that we
- // must start using the SoftReferences instead.
+ connection = m_connections.get( artifact );
if( connection == null )
{
// Not in cache. Why not? ---> Garbage Collection has
occurred.
@@ -266,11 +266,22 @@
}
}

- boolean timestamping = ( m_policy == Policy.TIMESTAMP );
- loader.loadResource( url, connection, destFile, timestamping );
+ return loader.loadResource( url, connection, dest );
}
}

+ /** Uploads the given file to the resource host as an artifact.
+ *
+ * @param artifact the artifact destination specification.
+ * @param source The input stream from where to read the content to be
uploaded.
+ * @exception IOException if an IO related error occurs
+ */
+ public void upload( Artifact artifact, InputStream source )
+ throws IOException
+ {
+ // TODO: implement upload through HTTP POST requests.
+ }
+
/** Checks if the Artifact is present on the resource host.
*
* <p>
@@ -289,13 +300,9 @@
*
* @return true if the artifact can be located, false otherwise.
*/
- public boolean checkPresence( Artifact artifact, File dest, boolean
knownOnly )
+ public boolean checkPresence( Artifact artifact, boolean knownOnly )
{
- if( dest.exists() && ( getDownloadPolicy() == Policy.FAST ) )
- {
- return true;
- }
- else if( "file".equals( m_baseUrl.getProtocol() ) )
+ if( "file".equals( m_baseUrl.getProtocol() ) )
{
return checkAtServer( artifact );
}
@@ -319,16 +326,6 @@
return m_enabled;
}

- /**
- * Get the timestamp policy.
- *
- * @return the timestamp policy
- */
- public Policy getDownloadPolicy()
- {
- return m_policy;
- }
-
/** Returns true if the ResourceHost is considered trusted.
*
* @return true if the ResourceHost is considered trusted.

Added:
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/ConnectionCache.java
==============================================================================
--- (empty file)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/ConnectionCache.java
Thu Mar 24 18:03:30 2005
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2004 Stephen J. McConnell.
+ * Copyright 2004 Niclas Hedhman
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.dpml.transit.artifact;
+
+import java.net.URLConnection;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+class ConnectionCache
+ implements Runnable
+{
+ static private Object DUMMY = new Object();
+ static private ConnectionCache m_instance;
+
+ private HashMap m_hardStore;
+ private WeakHashMap m_weakStore;
+
+ private long m_timeToLive;
+ private Thread m_thread;
+
+ static
+ {
+ m_instance = new ConnectionCache();
+ }
+
+ static ConnectionCache getInstance()
+ {
+ return m_instance;
+ }
+
+ private ConnectionCache()
+ {
+ m_hardStore = new HashMap();
+ m_weakStore = new WeakHashMap();
+ m_timeToLive = 30000;
+ }
+
+ URLConnection get( Artifact key )
+ {
+ synchronized( this ) // ensure no ConcurrentModificationException
can occur.
+ {
+ Entry entry = (Entry) m_hardStore.get( key );
+ if( entry == null )
+ return null;
+ URLConnection conn = entry.m_connection;
+ return conn;
+ }
+ }
+
+ void put( Artifact key, URLConnection conn )
+ {
+ synchronized( this ) // ensure no ConcurrentModificationException
can occur.
+ {
+ Entry entry = new Entry( conn );
+ m_hardStore.put( key, entry );
+ if( m_thread == null )
+ {
+ m_thread = new Thread( this, "ConnectionCache-cleaner" );
+ m_thread.setDaemon( true );
+ m_thread.start();
+ }
+ }
+ }
+
+ public void run()
+ {
+ while( true )
+ {
+ try
+ {
+ synchronized( this )
+ {
+ long now = System.currentTimeMillis();
+ Iterator list = m_hardStore.values().iterator();
+ while( list.hasNext() )
+ {
+ Entry entry = (Entry) list.next();
+ if( entry.m_collectTime < now )
+ {
+ m_weakStore.put( entry.m_connection, DUMMY );
+ list.remove();
+ }
+ }
+ if( m_hardStore.size() == 0 )
+ {
+ m_thread = null; // mark to start a new thread
next time.
+ break; // Exit the thread
+ }
+ wait( 10000 );
+ }
+ } catch( Exception e )
+ {
+ // Can not happen?
+ // Just ignore and it will be handled in the next round.
+ e.printStackTrace();
+ }
+ }
+ }
+
+ class Entry
+ {
+ private URLConnection m_connection;
+ private long m_collectTime;
+
+ Entry( URLConnection conn )
+ {
+ m_connection = conn;
+ m_collectTime = System.currentTimeMillis() + m_timeToLive;
+ }
+
+ public boolean equals( Object obj )
+ {
+ if( obj == null )
+ return false;
+ if( obj.getClass().equals( Entry.class ) == false )
+ return false;
+ Entry other = (Entry) obj;
+
+ if( m_connection.equals( other.m_connection ) == false )
+ return false;
+
+ return true;
+ }
+
+ public int hashCode()
+ {
+ return m_connection.hashCode();
+ }
+
+ public String toString()
+ {
+ return "Entry[" + m_connection + ", " + m_collectTime + "]";
+ }
+ }
+}

Added:
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/EclipseResolver.java
==============================================================================
--- (empty file)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/EclipseResolver.java
Thu Mar 24 18:03:30 2005
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2004 Stephen J. McConnell.
+ * Copyright 2004 Niclas Hedhman.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.dpml.transit.artifact;
+
+/** The EclipseResolver decodes artifacts into the Eclipse specified layout
+ * of artifacts on a file system or http server.
+ * This format says that for an artifact
<code>artifact:[type]:[group]/[name]#[version]</code>
+ * the location of such artifact would be;
+ * <code>[group]-[version]/[name].[type]</code>.
+ * Example;
<code>artifact:jar:eclipse/plugins/eclipse-osgi-runtime/core#3.1.0</code>
+ * would return the path
<code>eclipse/plugins/eclipse-osgi-runtime-3.1.0/core.jar</code>.
+ */
+public class EclipseResolver
+ implements LocationResolver
+{
+ /**
+ * Return the base path for an artifact. The base path is derived from
+ * the artifact group and version. For an artifact group of
"metro/cache" and a
+ * version equal to "1.3", the base value will be translated using the
pattern
+ * "[group]-[version]" to form "metro/cache-1.3". The base path value
represents
+ * the directory path relative to a repository root of the directory
containing
+ * this artifact.
+ *
+ * @return the base path
+ */
+ public final String resolveBase( Artifact artifact )
+ {
+ return artifact.getGroup() + "-" + artifact.getVersion();
+ }
+
+ /**
+ * Returns the full path of the artifact relative to a logical root
directory.
+ * The full path is equivalent to the base path and artifact filename
using the
+ * pattern "[base]/[filename]". Path values may be used to resolve an
artifact
+ * from a remote repository or local cache relative to the repository or
cache
+ * root. An artifact such as
+ *
<code>artifact:jar:eclipse/plugins/eclipse-osgi-runtime/core#3.1.0</code>
+ * would return the path
+ * <code>eclipse/plugins/eclipse-osgi-runtime-3.1.0/core.jar</code>.
+ *
+ * @see #getBase
+ * @see #getFilename
+ * @return the logical artifact path
+ */
+ public final String resolvePath( Artifact artifact )
+ {
+ return resolveBase( artifact ) + "/" + resolveFilename( artifact );
+ }
+
+ /**
+ * Return the expanded filename of the artifact.
+ * The filename is expressed as <code>[name].[type]</code>.
+ *
+ * @return the artifact expanded filename
+ */
+ public String resolveFilename( Artifact artifact )
+ {
+ return artifact.getName() + "." + artifact.getType();
+ }
+}

Modified:
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/FileCacheHandler.java
==============================================================================
---
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/FileCacheHandler.java
(original)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/FileCacheHandler.java
Thu Mar 24 18:03:30 2005
@@ -19,14 +19,23 @@

package net.dpml.transit.artifact;

+import java.io.BufferedInputStream;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
import java.io.IOException;
+import java.io.OutputStream;

+import java.util.Date;
import java.util.Map;
import java.util.Iterator;
import java.util.Properties;
import java.util.TreeMap;

+import java.util.zip.ZipFile;
+import java.util.zip.ZipEntry;
+
import net.dpml.lang.NullArgumentException;

import net.dpml.transit.Transit;
@@ -57,6 +66,8 @@

private LocationResolver m_resolver;

+ private ZipCache m_zipCache;
+
//
------------------------------------------------------------------------
// constructor
//
------------------------------------------------------------------------
@@ -69,6 +80,8 @@
*/
public FileCacheHandler( Monitor monitor, ResourceHost[] hosts,
Properties props, LocationResolver resolver )
{
+ m_zipCache = new ZipCache();
+
m_resolver = resolver;
m_resourceHosts = new TreeMap();
for( int i=0; i < hosts.length; i++ )
@@ -127,64 +140,53 @@
* the first repository does not have the artifact in question.
*
* @param artifact the artifact to retrieve and cache
- * @return file referencing the local resource
+ * @return input stream containing the artifact content.
* @exception IOException if an IO error occurs.
* @exception TransitException if a transit system error occurs.
* @exception NullArgumentException if the artifact argument is null.
*/
- public File getResource( Artifact artifact )
+ public InputStream getResource( Artifact artifact )
throws IOException, TransitException, NullArgumentException
{
CacheMonitorRouter monitor =
Transit.getInstance().getCacheMonitorRouter();
- if( null == artifact )
- {
- throw new NullArgumentException( "artifact" );
- }
-
if( monitor != null )
{
monitor.resourceRequested( artifact );
}

+ if( null == artifact )
+ {
+ throw new NullArgumentException( "artifact" );
+ }
String path = m_resolver.resolvePath( artifact );
File destination = new File( m_cacheDir, path );
+ File parentDir = destination.getParentFile();
+ parentDir.mkdirs();
boolean exist = destination.exists();
-
- ResourceHost known = findKnownGroupHost( artifact, destination );
-
- boolean success = download( known, artifact, destination );
- if( !success )
+ boolean success;
+ if( exist )
{
- ResourceHost any = findAnyPresence( artifact, destination );
- success = download( any, artifact, destination );
+ success = true;
}
-
- if( success )
+ else
{
- if( !destination.exists() )
+ ResourceHost known = findKnownGroupHost( artifact );
+ success = download( known, artifact, destination );
+ if( !success )
{
- String error =
- "Download successful reported, "
- + "but the destination does not exist: "
- + artifact + ", " + destination;
- throw new InternalError( error );
+ ResourceHost any = findAnyPresence( artifact );
+ success = download( any, artifact, destination );
}
- if( monitor != null )
- {
- if( exist )
- {
- monitor.updatedLocalCache( artifact.toURL(), destination
);
- }
- else
- {
- monitor.addedToLocalCache( artifact.toURL(), destination
);
- }
- }
- return destination;
}
- else if( exist )
+ if( success )
+ {
+ checkInternalConsistency( artifact, destination );
+ endNotifyMonitor( monitor, exist, artifact, destination );
+ }
+ if( destination.exists() )
{
- return destination;
+ FileInputStream stream = new FileInputStream( destination );
+ return new BufferedInputStream( stream );
}

if( monitor != null )
@@ -192,13 +194,86 @@
monitor.failedDownload( artifact );
}

- String error =
- "Unresolvable artifact: ["
- + artifact
- + "].";
+ String error = "Unresolvable artifact: [" + artifact + "].";
throw new ArtifactNotFoundException( error, artifact );
}

+ /**
+ * Attempts to download and cache a remote artifact using a set of remote
+ * repositories.
+ * <p>
+ * This method allows an internal reference to be passed to the
+ * cache handler and it is expected to return the InputStream of the
+ * internal item inside Jar/Zip files. If this method is called, the
+ * implementation can assume that the artifact is a Zip file.
+ * </p>
+ *
+ * @param artifact the artifact to retrieve and cache
+ * @param internalReference referencing a item within the artifact. This
+ * argument may start with "!" or "!/", which should be ignored.
+ * @return a file referencing the local resource
+ * @exception IOException if an IO error occurs
+ * @exception TransitException is a transit system error occurs
+ */
+ public InputStream getResource( Artifact artifact, String
internalReference )
+ throws IOException, TransitException
+ {
+ synchronized( this )
+ {
+ if( internalReference.startsWith( "!" ) )
+ internalReference = internalReference.substring( 1 );
+ if( internalReference.startsWith( "/" ) )
+ internalReference = internalReference.substring( 1 );
+
+ ZipFile zip = m_zipCache.get( artifact );
+ if( zip == null )
+ {
+ InputStream artifactStream = getResource( artifact );
+ File tmpFile = File.createTempFile( "~dpml", ".tmp" );
+ tmpFile.deleteOnExit();
+ FileOutputStream fos = new FileOutputStream( tmpFile );
+ StreamUtils.copyStream( artifactStream, fos, true );
+ zip = new ZipFile( tmpFile );
+ m_zipCache.put( artifact, zip );
+ }
+ ZipEntry entry = zip.getEntry( internalReference );
+ InputStream stream = zip.getInputStream( entry );
+ return new BufferedInputStream( stream );
+ }
+
+ }
+
+ /** Creates an output stream to where the artifact content can be written
+ * to.
+ * <p>
+ * If the artifact already exists, a
<code>ArtifactAlreadyExistsException</code>
+ * will be thrown. If the directory doesn't exists, it will be created.
+ * </p>
+ * @exception IOException if an IO error occurs.
+ * @exception NullArgumentException if the artifact argument is null.
+ * @exception ArtifactAlreadyExistsException if the artifact already
exists
+ * in the cache.
+ */
+ public OutputStream createOutputStream( Artifact artifact )
+ throws NullArgumentException, ArtifactAlreadyExistsException,
IOException
+ {
+ if( null == artifact )
+ {
+ throw new NullArgumentException( "artifact" );
+ }
+ ResourceHost any = findAnyPresence( artifact );
+ if( any != null )
+ throw new ArtifactAlreadyExistsException( "Artifact found on
server.", artifact );
+ String path = m_resolver.resolvePath( artifact );
+ File destination = new File( m_cacheDir, path );
+ if( destination.exists() )
+ throw new ArtifactAlreadyExistsException( "Artifact found in
cache.", artifact );
+ File parentDir = destination.getParentFile();
+ if( !parentDir.exists() )
+ parentDir.mkdirs();
+ return new FileOutputStream( destination );
+ }
+
//
------------------------------------------------------------------------
// implementation
//
------------------------------------------------------------------------
@@ -209,7 +284,7 @@
* @param dest the destination cached file
* @return the resource host (possibly null)
*/
- private ResourceHost findKnownGroupHost( Artifact artifact, File dest )
+ private ResourceHost findKnownGroupHost( Artifact artifact )
{
Iterator list = m_resourceHosts.values().iterator();
while ( list.hasNext() )
@@ -217,7 +292,7 @@
ResourceHost host = (ResourceHost) list.next();
if( host.isEnabled() )
{
- if( host.checkPresence( artifact, dest, true ) )
+ if( host.checkPresence( artifact, true ) )
{
return host;
}
@@ -232,7 +307,7 @@
* @param dest the destination cached file
* @return the resource host (possibly null)
*/
- private ResourceHost findAnyPresence( Artifact artifact, File dest )
+ private ResourceHost findAnyPresence( Artifact artifact )
{
Iterator list = m_resourceHosts.values().iterator();
while ( list.hasNext() )
@@ -240,7 +315,7 @@
ResourceHost host = (ResourceHost) list.next();
if( host.isEnabled() )
{
- if( host.checkPresence( artifact, dest, false ) )
+ if( host.checkPresence( artifact, false ) )
{
return host;
}
@@ -265,14 +340,25 @@
{
return false;
}
+ File parentDir = destination.getParentFile();
+ File tempFile = File.createTempFile( "~dpml", ".tmp", parentDir );
+ tempFile.deleteOnExit(); // safety harness in case we abort
abnormally
+ // like a Ctrl-C.
+ FileOutputStream tempOut = new FileOutputStream( tempFile );
+
CacheMonitorRouter monitor =
Transit.getInstance().getCacheMonitorRouter();
try
{
- host.download( artifact, destination );
+ Date lastModified = host.download( artifact, tempOut );
+ // An atomic operation and no risk of a corrupted
+ // artifact content.
+ tempFile.renameTo( destination );
+ destination.setLastModified( lastModified.getTime() );
return true;
}
catch( IOException e )
{
+ tempFile.delete();
if( monitor != null )
{
monitor.failedDownloadFromHost( host.toString(), artifact, e
);
@@ -302,4 +388,31 @@
cachedir.mkdirs();
return cachedir;
}
+
+ private void endNotifyMonitor( CacheMonitorRouter monitor, boolean
existed,
+ Artifact artifact, File destination )
+ {
+ if( monitor != null )
+ {
+ if( existed )
+ {
+ monitor.updatedLocalCache( artifact.toURL(), destination );
+ }
+ else
+ {
+ monitor.addedToLocalCache( artifact.toURL(), destination );
+ }
+ }
+ }
+
+ private void checkInternalConsistency( Artifact artifact, File
destination )
+ {
+ if( destination.exists() )
+ return;
+ String error = "Download reported [success], but the destination
does not exist: "
+ + artifact + ", " + destination;
+ throw new InternalError( error );
+ }
+
+
}

Modified:
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/NetworkLoader.java
==============================================================================
---
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/NetworkLoader.java
(original)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/NetworkLoader.java
Thu Mar 24 18:03:30 2005
@@ -19,7 +19,6 @@
package net.dpml.transit.artifact;

import java.io.File;
-import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
@@ -28,6 +27,8 @@
import java.net.URL;
import java.net.URLConnection;

+import java.util.Date;
+
import net.dpml.transit.Transit;
import net.dpml.transit.TransitException;

@@ -38,28 +39,11 @@
*/
class NetworkLoader
{
- //
------------------------------------------------------------------------
- // static
- //
------------------------------------------------------------------------
-
- /**
- * Buffer size.
- */
- private static final int BUFFER_SIZE = 102400;
-
- //
------------------------------------------------------------------------
- // state
- //
------------------------------------------------------------------------
-
/**
* Network monitor router.
*/
private NetworkMonitorRouter m_monitor;

- //
------------------------------------------------------------------------
- // constructor
- //
------------------------------------------------------------------------
-
/**
* Creation of a new network loader.
* @exception TransitException if an error in transit system
establishment occurs
@@ -80,194 +64,27 @@
* @param url the of the file to retrieve
* @param connection the url connection
* @param destination where to store it
- * @param timestamping the timestamping policy
- * @return the url of the local destination
+ * @return the lastModified date of the downloaded artifact.
* @exception ArtifactException if an artifact related errror occurs
* @exception IOException if an IO error occurs
*/
- URL loadResource( URL url, URLConnection connection, File destination,
boolean timestamping )
+ Date loadResource( URL url, URLConnection connection, OutputStream
destination )
throws ArtifactException, IOException
{
- long remoteTimestamp = 0;
-
- //
- // if timestamp is enabled and the destination file exists and
- // the source is a file - then do a quick check using native File
- // last modification dates to see if anything needs to be done
- //
-
- String protocol = url.getProtocol();
- if( timestamping && protocol.equals( "file" ) )
- {
- try
- {
- String sourcePath = url.getPath();
- File sourceFile = new File( sourcePath );
- if( destination.exists() )
- {
- if( destination.lastModified() >=
sourceFile.lastModified() )
- {
- return destination.toURL();
- }
- }
-
- //
- // set the remote tamestamp here because the precision
- // for a file last modification date is higher then the
- // connection last modification date
- //
-
- remoteTimestamp = sourceFile.lastModified();
-
- }
- catch( Throwable e )
- {
- final String error =
- "Unexpected error while handling resource request.";
- throw new ArtifactException( error, e );
- }
- }
-
- //set the timestamp to the file date.
- long localTimestamp = 0;
- boolean hasTimestamp = false;
- if( destination.exists() )
- {
- localTimestamp = destination.lastModified();
- hasTimestamp = true;
- }
-
- //modify the headers
- //NB: things like user authentication could go in here too.
-
if( connection instanceof HttpURLConnection )
{
- if( timestamping && hasTimestamp )
- {
- connection.setIfModifiedSince( localTimestamp );
- }
-
- //next test for a 304 result (HTTP only)
- HttpURLConnection httpConnection = ( HttpURLConnection )
connection;
-
+ HttpURLConnection httpConnection = (HttpURLConnection)
connection;
int code = httpConnection.getResponseCode();
- if( timestamping )
- {
- if( code == HttpURLConnection.HTTP_NOT_MODIFIED )
- {
- return destination.toURL();
- }
- }
// test for 401 result (HTTP only)
if ( code == HttpURLConnection.HTTP_UNAUTHORIZED )
{
throw new IOException( "Not authorized." );
}
}
-
InputStream in = connection.getInputStream();
-
- File parent = destination.getParentFile();
- parent.mkdirs();
-
- File tempFile = File.createTempFile( "~metro", ".tmp", parent );
- tempFile.deleteOnExit(); // safety harness in case we abort
abnormally
- // like a Ctrl-C.
-
- FileOutputStream tempOut = new FileOutputStream( tempFile );
-
int expected = connection.getContentLength();
- copyStream( url, expected, in, tempOut, true );
-
- // An atomic operation and no risk of a corrupted
- // artifact content.
-
- tempFile.renameTo( destination );
-
- // if (and only if) the use file time option is set, then the
- // saved file now has its timestamp set to that of the downloaded
- // file
-
- if( timestamping )
- {
- if( remoteTimestamp == 0 )
- {
- remoteTimestamp = connection.getLastModified();
- }
-
- if( remoteTimestamp < 0 )
- {
- destination.setLastModified( System.currentTimeMillis() );
- }
- else
- {
- destination.setLastModified( remoteTimestamp );
- }
- }
- return destination.toURL();
- }
-
- /**
- * Copy a stream.
- * @param source the source url
- * @param expected the expected size in bytes
- * @param src the source input stream
- * @param dest the destination output stream
- * @param closeStreams TRUE if the streams should be closed on completion
- * @exception IOException if an IO error occurs
- */
- private void copyStream( URL source, int expected, InputStream src,
- OutputStream dest, boolean closeStreams )
- throws IOException
- {
- int length;
- int count = 0; // cumulative total read
- byte[] buffer = new byte[BUFFER_SIZE];
- try
- {
- while ( ( length = src.read( buffer ) ) >= 0 )
- {
- count = count + length;
- dest.write( buffer, 0, length );
- if( null != m_monitor )
- {
- m_monitor.notifyUpdate( source, expected, count );
- }
- }
- }
- finally
- {
- if( closeStreams )
- {
- if( null != src )
- {
- try
- {
- src.close();
- }
- catch( Throwable e )
- {
- // ignore
- boolean ignorable = true;
- }
- }
- if( null != dest )
- {
- try
- {
- dest.close();
- }
- catch( Throwable e )
- {
- // ignore
- boolean ignorable = true;
- }
- }
- }
- if( null != m_monitor )
- {
- m_monitor.notifyCompletion( source );
- }
- }
+ StreamUtils.copyStream( m_monitor, url, expected, in, destination,
true );
+ long remoteTimestamp = connection.getLastModified();
+ return new Date( remoteTimestamp );
}
}

Modified:
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/RemoteCacheHandler.java
==============================================================================
---
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/RemoteCacheHandler.java
(original)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/RemoteCacheHandler.java
Thu Mar 24 18:03:30 2005
@@ -19,8 +19,9 @@

package net.dpml.transit.artifact;

-import java.io.File;
+import java.io.InputStream;
import java.io.IOException;
+import java.io.OutputStream;

import java.util.Map;
import java.util.Iterator;
@@ -86,10 +87,46 @@
* @exception TransitException if a transit system error occurs.
* @exception NullArgumentException if the artifact argument is null.
*/
- public File getResource( Artifact artifact )
+ public InputStream getResource( Artifact artifact )
throws IOException, TransitException, NullArgumentException
{
return m_delegate.getResource( artifact );
}

+ /**
+ * Attempts to download and cache a remote artifact using a set of remote
+ * repositories. The operation is not fail fast and so it keeps trying
if
+ * the first repository does not have the artifact in question.
+ *
+ * @param artifact the artifact to retrieve and cache
+ * @return file referencing the local resource
+ * @exception IOException if an IO error occurs.
+ * @exception TransitException if a transit system error occurs.
+ * @exception NullArgumentException if the artifact argument is null.
+ */
+ public InputStream getResource( Artifact artifact, String internalRef )
+ throws IOException, TransitException, NullArgumentException
+ {
+ return m_delegate.getResource( artifact, internalRef );
+ }
+
+ /** Creates an output stream to where the artifact content can be written
+ * to.
+ * <p>
+ * If the artifact already exists, a
<code>ArtifactAlreadyExistsException</code>
+ * will be thrown. If the directory doesn't exists, it will be created.
+ * The CacheHandler is responsible to recognize the completion of the
+ * writes through the <code>close()</code> method in the output stream,
+ * and do any post-processing there.
+ * </p>
+ * @exception NullArgumentException if the artifact argument is null.
+ * @exception ArtifactAlreadyExistsException if the artifact already
exists
+ * in the cache.
+ */
+ public OutputStream createOutputStream( Artifact artifact )
+ throws NullArgumentException, ArtifactAlreadyExistsException,
IOException, RemoteException
+ {
+ return m_delegate.createOutputStream( artifact );
+ }
+
}

Modified:
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/ResourceHost.java
==============================================================================
---
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/ResourceHost.java
(original)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/ResourceHost.java
Thu Mar 24 18:03:30 2005
@@ -18,17 +18,21 @@

package net.dpml.transit.artifact;

-import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.io.IOException;
+
import java.net.URL;

-/**
+import java.util.Date;
+
+/**
* An interface that represents locations where the artifacts can be
* downloaded.
*/
public interface ResourceHost
{
- /** Downloads the given artifact to the directory indicated.
+ /** Downloa ds 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
@@ -39,10 +43,20 @@
* group is known to exist on this resource host.
* </p>
* @param artifact the artifact that is requested to be downloaded.
- * @param destFile The file where to place the downloaded content.
+ * @param dest The output stream where to write the downloaded content.
* @exception IOException if an IO related error occurs
+ * @return the lastModified date of the downloaded artifact.
*/
- void download( Artifact artifact, File destFile )
+ Date download( Artifact artifact, OutputStream dest )
+ throws IOException;
+
+ /** Uploads the given file to the resource host as an artifact.
+ *
+ * @param artifact the artifact destination specification.
+ * @param source The input stream from where to read the content to be
uploaded.
+ * @exception IOException if an IO related error occurs
+ */
+ void upload( Artifact artifact, InputStream source )
throws IOException;

/** Checks if the Artifact is present on the resource host.
@@ -57,13 +71,12 @@
* </p>
*
* @param artifact the artifact for which the method checks its presence.
- * @param dest the destination cached file
* @param knownOnly does not perform a remote connection, and instead
lookup
* the group table, and if not found there it will return false.
*
* @return true if the artifact can be located, false otherwise.
*/
- boolean checkPresence( Artifact artifact, File dest, boolean knownOnly );
+ boolean checkPresence( Artifact artifact, boolean knownOnly );

/** Returns the hostname of the resource host.
*
@@ -75,7 +88,7 @@
*/
String getHostName();

- /**
+ /**
* Returns the full host url.
*
* @return the host url
@@ -89,13 +102,6 @@
*/
boolean isEnabled();

- /**
- * Get the timestamp policy.
- *
- * @return the timestamp policy
- */
- Policy getDownloadPolicy();
-
/** Returns true if the ResourceHost is considered trusted.
* @return true if the host is trusted
*/

Modified:
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/ResourceHostFactory.java
==============================================================================
---
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/ResourceHostFactory.java
(original)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/ResourceHostFactory.java
Thu Mar 24 18:03:30 2005
@@ -111,7 +111,9 @@

/**
* Create a set of resource hosts relative to the information optained at
the
- * authorative anchor. The implementation will attempt to locate a
hosts.xml
+ * authorative anchor.
+ * <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
@@ -121,6 +123,7 @@
* authorative url is not the "file:" protocol then the implementation
will attempt
* to locate a resource named "index.lst" containing a set of host
descriptor filenames
* to evaluation.
+ * </p>
*
* @return the resolve set of resource hosts
* @exception IOException if an io error occurs
@@ -187,8 +190,9 @@
* dpml.transit.resourcehost.priority=[priority]
* dpml.transit.resourcehost.username=[username]
* dpml.transit.resourcehost.password=[password]
- * dpml.transit.resourcehost.scheme=[scheme]
+ * dpml.transit.resourcehost.scheme=[authentication scheme]
* dpml.transit.resourcehost.prompt=[prompt/realm]
+ * dpml.transit.resourcehost.resolver=[resolver-classname]
* </pre>
* @param result the list of established hosts
* @param files the set of filesname to scan
@@ -232,6 +236,9 @@
* dpml.transit.resourcehost.priority=[priority]
* dpml.transit.resourcehost.username=[username]
* dpml.transit.resourcehost.password=[password]
+ * dpml.transit.resourcehost.scheme=[authentication scheme]
+ * dpml.transit.resourcehost.prompt=[prompt/realm]
+ * dpml.transit.resourcehost.resolver=[resolver-classname]
* </pre>
* @param result the list of established hosts
* @param base the base directory from within which host files will be
located
@@ -259,6 +266,7 @@
* dpml.transit.resourcehost.password=[password]
* dpml.transit.resourcehost.scheme=[authentication scheme]
* dpml.transit.resourcehost.prompt=[prompt/realm]
+ * dpml.transit.resourcehost.resolver=[resolver-classname]
* </pre>
* @param result the list of established hosts
* @param files the set of host descriptors to read
@@ -359,12 +367,12 @@
}
catch( MalformedURLException e )
{
- final String error =
- "The value assigned to the base host property within a host
definition file is invalid."
- + "\n Source: "
+ final String error =
+ "The value assigned to the base host property within a host
definition file is invalid."
+ + "\n Source: "
+ hostDef
- + "\n Property: dpml.transit.resourcehost.base"
- + "\n Value: "
+ + "\n Property: dpml.transit.resourcehost.base"
+ + "\n Value: "
+ base;
throw new TransitException( error, e );
}
@@ -401,6 +409,7 @@
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.artifact.ClassicResolver" );

boolean enabled =
Util.getProperty(
@@ -408,20 +417,12 @@
boolean trusted =
Util.getProperty(
props, "dpml.transit.resourcehost.trusted", "false"
).equalsIgnoreCase( TRUE_VALUE );
- String policyType =
- Util.getProperty( props, "dpml.transit.resourcehost.policy",
"fast" );
- if( "".equals( policyType ) )
- {
- policyType = "fast";
- }
-
- Policy policy = Policy.createPolicy( policyType );

try
{
return createResourceHost(
- classname, baseUrl, groupFile, priority, policy, enabled,
trusted,
- username, password, scheme, prompt );
+ classname, baseUrl, groupFile, priority, enabled, trusted,
+ username, password, scheme, prompt, resolverclass );
}
catch( Throwable e )
{
@@ -504,7 +505,6 @@
* @param base the base url of the host
* @param index the url of group index resource
* @param priority the assigned host priority
- * @param policy the assigned timestamp policy
* @param enabled if true the created host is enabled else disabled
* @param trusted if the host is trusted
* @param username the authentication username
@@ -516,24 +516,25 @@
* @exception IOException if an IO related error occurs
*/
ResourceHost createResourceHost(
- String classname, URL base, URL index, int priority, Policy policy,
+ String classname, URL base, URL index, int priority,
boolean enabled, boolean trusted, String username, String password,
- String scheme, String prompt )
+ String scheme, String prompt, String resolverClassname )
throws TransitException, IOException
{
+ LocationResolver resolver = createResolver( resolverClassname );
String[] groups = getKnownGroups( index );
Class[] types = new Class[]
{
URL.class,
String[].class,
Integer.TYPE,
- Policy.class,
Boolean.TYPE,
Boolean.TYPE,
String.class,
String.class,
String.class,
- String.class
+ String.class,
+ LocationResolver.class
};

Object[] args = new Object[]
@@ -541,13 +542,13 @@
base,
groups,
new Integer( priority ),
- policy,
enabled ? Boolean.TRUE : Boolean.FALSE,
trusted ? Boolean.TRUE : Boolean.FALSE,
username,
password,
scheme,
- prompt
+ prompt,
+ resolver
};

try
@@ -620,4 +621,24 @@
throw new TransitException( error, e.getTargetException() );
}
}
+
+ private LocationResolver createResolver( String classname )
+ throws TransitException
+ {
+ try
+ {
+ Class cls = getClass().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
);
+ }
+
+ }
}

Modified:
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/SecuredTransitContext.java
==============================================================================
---
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/SecuredTransitContext.java
(original)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/SecuredTransitContext.java
Thu Mar 24 18:03:30 2005
@@ -132,10 +132,6 @@
*/
private static final String TRANSIT_NAME = "transit";

- /**
- * Transit cache handler service JNDI name.
- */
- private static final String TRANSIT_JNDI_NAME = "rmi://localhost:1099/"
+ TRANSIT_NAME;

//------------------------------------------------------------------
// state
@@ -151,13 +147,18 @@
*/
private URL m_authorativeHost;

+ private boolean m_server;
+
/**
* Return the singleton context.
* @return the secure context
*/
public static SecuredTransitContext getInstance()
{
- return m_CONTEXT;
+ synchronized( SecuredTransitContext.class )
+ {
+ return m_CONTEXT;
+ }
}

//------------------------------------------------------------------
@@ -175,7 +176,36 @@
public static SecuredTransitContext create()
throws TransitException
{
- return SecuredTransitContext.create( false, new SystemMonitor() );
+ synchronized( SecuredTransitContext.class )
+ {
+ return SecuredTransitContext.create( new SystemMonitor() );
+ }
+ }
+
+ /** Set the Transit instance into Server mode.
+ * @param serverMode true to operate Transit in Server mode.
+ * @exception TransitException if not possible to make this Transit into
a server.
+ */
+ public void setServer( boolean serverMode )
+ throws TransitException
+ {
+ m_server = serverMode;
+ if( m_server ^ serverMode ) // Is there a change?
+ {
+ if( m_server )
+ {
+ bindServer();
+ }
+ else
+ {
+ unbindServer();
+ }
+ }
+ }
+
+ public boolean isServer()
+ {
+ return m_server;
}

/**
@@ -190,34 +220,33 @@
* @exception NullArgumentException if the supplied monitor is null and
an instance
* of this class has not been created already.
*/
- public static SecuredTransitContext create( boolean server, final
SystemMonitor monitor )
+ public static SecuredTransitContext create( final SystemMonitor monitor )
throws TransitException, NullArgumentException
{
- if( m_CONTEXT != null )
- {
- return m_CONTEXT;
- }
- if( null == monitor )
- {
- throw new NullArgumentException( "monitor" );
- }
- if( monitor.isTraceEnabled() )
+ synchronized( SecuredTransitContext.class )
{
- monitor.trace( "creating secure transit context" );
- }
+ if( m_CONTEXT != null )
+ {
+ return m_CONTEXT;
+ }
+ if( null == monitor )
+ {
+ throw new NullArgumentException( "monitor" );
+ }
+ if( monitor.isTraceEnabled() )
+ {
+ monitor.trace( "creating secure transit context" );
+ }

- if( !server )
- {
// if the cache service is available on localhost then use it
otherwise
// continue with the classic per jvm approach
-
try
{
- Registry reg = LocateRegistry.getRegistry();
+ Registry reg = LocateRegistry.getRegistry( 1099 );
CacheHandler handler = (CacheHandler) reg.lookup(
TRANSIT_NAME );
if( monitor.isTraceEnabled() )
{
- monitor.trace( "binding to shared cache handler" );
+ monitor.trace( "binding to shared cache handler" );
}
m_CONTEXT = new SecuredTransitContext( handler );
return m_CONTEXT;
@@ -235,50 +264,29 @@
// Ignore and continue
System.out.println( "SJM: Could not find the
RemoteCacheHandler." );
}
- }

- // proceed with context establishment
+ // proceed with context establishment


- try
- {
- URL authorative = establishAuthority( monitor );
- monitor.notifyAuthority( authorative );
- Properties props = getTransitProperties( authorative );
- String classname = getResourceManagerClassname( props );
- ResourceManager manager = createResourceManager( classname,
authorative, monitor );
- CacheHandler ch = manager.createCacheHandler();
- monitor.notifyCacheHandlerCreation( ch );
- m_CONTEXT = new SecuredTransitContext( authorative, ch, props );
- }
- catch( IOException e )
- {
- String error = "Unable to establish the SecuredTransitContext.";
- throw new TransitException( error, e );
- }
-
- if( server )
- {
- // publish the cache handler as a remotely accessible service on
localhost
- // (need to fix this with Nicals)
-
try
{
- CacheHandler lch = m_CONTEXT.getCacheHandler();
- RemoteCacheHandler rch = new RemoteCacheHandler( lch );
- Registry reg = LocateRegistry.createRegistry( 1099 );
- reg.bind( TRANSIT_NAME, rch );
- System.out.println( "# server registered on port 1099 as: "
+ TRANSIT_JNDI_NAME );
+ URL authorative = establishAuthority( monitor );
+ monitor.notifyAuthority( authorative );
+ Properties props = getTransitProperties( authorative );
+ String classname = getResourceManagerClassname( props );
+ ResourceManager manager = createResourceManager( classname,
authorative, monitor );
+ CacheHandler ch = manager.createCacheHandler();
+ monitor.notifyCacheHandlerCreation( ch );
+ m_CONTEXT = new SecuredTransitContext( authorative, ch,
props );
}
- catch( Throwable e )
+ catch( IOException e )
{
- final String error =
- "Could not establish the cache handler as a remote
service.";
+ String error = "Unable to establish the
SecuredTransitContext.";
throw new TransitException( error, e );
}
- }

- return m_CONTEXT;
+ return m_CONTEXT;
+ }
}

/**
@@ -700,4 +708,45 @@
return id;
}

+ private void unbindServer()
+ throws TransitException
+ {
+ try
+ {
+ Registry reg = LocateRegistry.getRegistry( 1099 );
+ reg.unbind( TRANSIT_NAME );
+ }
+ catch( Throwable e )
+ {
+ String error = "Could not remove the cache handler as a remote
service.";
+ throw new TransitException( error, e );
+ }
+ }
+
+ private void bindServer()
+ throws TransitException
+ {
+ // publish the cache handler as a remotely accessible
+ // service on localhost
+ try
+ {
+ try
+ {
+ Registry reg = LocateRegistry.createRegistry( 1099 );
+ } catch( Throwable t )
+ {} // ignore
+
+ CacheHandler lch = m_CONTEXT.getCacheHandler();
+ RemoteCacheHandler rch = new RemoteCacheHandler( lch );
+ Registry reg = LocateRegistry.getRegistry( 1099 );
+ reg.bind( TRANSIT_NAME, rch );
+ System.out.println( "# server registered on port 1099 as: " +
TRANSIT_NAME );
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "Could not establish the cache handler as a remote service.";
+ throw new TransitException( error, e );
+ }
+ }
}

Added:
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/StreamUtils.java
==============================================================================
--- (empty file)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/StreamUtils.java
Thu Mar 24 18:03:30 2005
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2004 Stephen J. McConnell.
+ * Copyright 2004 Niclas Hedhman
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.dpml.transit.artifact;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import java.net.URL;
+
+import net.dpml.lang.NullArgumentException;
+
+import net.dpml.transit.monitors.NetworkMonitor;
+
+class StreamUtils
+{
+ /**
+ * Buffer size.
+ */
+ private static final int BUFFER_SIZE = 102400;
+
+
+ /** Copy a stream.
+ * @param source the source url
+ * @param expected the expected size in bytes
+ * @param src the source input stream
+ * @param dest the destination output stream
+ * @param closeStreams TRUE if the streams should be closed on completion
+ * @exception IOException if an IO error occurs
+ */
+ static void copyStream( InputStream src, OutputStream dest, boolean
closeStreams )
+ throws IOException, NullArgumentException
+ {
+ copyStream( null, null, 0, src, dest, closeStreams );
+ }
+
+ /** Copy a stream.
+ * @param source the source url
+ * @param expected the expected size in bytes
+ * @param src the source input stream
+ * @param dest the destination output stream
+ * @param closeStreams TRUE if the streams should be closed on completion
+ * @exception IOException if an IO error occurs
+ */
+ static void copyStream( NetworkMonitor monitor, URL source, int expected,
+ InputStream src, OutputStream dest, boolean
closeStreams )
+ throws IOException, NullArgumentException
+ {
+ if( src == null )
+ {
+ throw new NullArgumentException( "src" );
+ }
+
+ if( dest == null )
+ {
+ throw new NullArgumentException( "dest" );
+ }
+
+ int length;
+ int count = 0; // cumulative total read
+ byte[] buffer = new byte[BUFFER_SIZE];
+ if( dest instanceof BufferedOutputStream == false )
+ {
+ dest = new BufferedOutputStream( dest );
+ }
+ if( src instanceof BufferedInputStream == false )
+ {
+ src = new BufferedInputStream( src );
+ }
+
+ try
+ {
+ while ( ( length = src.read( buffer ) ) >= 0 )
+ {
+ count = count + length;
+ dest.write( buffer, 0, length );
+ if( null != monitor )
+ {
+ monitor.notifyUpdate( source, expected, count );
+ }
+ }
+ }
+ finally
+ {
+ if( closeStreams )
+ {
+ try
+ {
+ src.close();
+ }
+ catch( Throwable e )
+ {
+ // ignore
+ boolean ignorable = true;
+ }
+
+ try
+ {
+ dest.close();
+ }
+ catch( Throwable e )
+ {
+ // ignore
+ boolean ignorable = true;
+ }
+ }
+ if( null != monitor )
+ {
+ monitor.notifyCompletion( source );
+ }
+ }
+ }
+}

Modified:
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/XMLHostsBuilder.java
==============================================================================
---
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/XMLHostsBuilder.java
(original)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/XMLHostsBuilder.java
Thu Mar 24 18:03:30 2005
@@ -111,10 +111,10 @@
throws IOException, TransitException
{
String classname = getClassname( element );
+ String resolverclass = getResolverClass( element );
URL base = getBaseURL( element );
URL index = getKnownGroupsURL( element );
int priority = getPriority( element );
- Policy policy = getPolicy( element );
boolean enabled = getEnabled( element );
boolean trusted = getTrusted( element );
String username = getUsername( element );
@@ -123,8 +123,8 @@
String prompt = getPrompt( element );

return m_resourceHostFactory.createResourceHost(
- classname, base, index, priority, policy, enabled, trusted,
- username, password, scheme, prompt );
+ classname, base, index, priority, enabled, trusted,
+ username, password, scheme, prompt, resolverclass );
}

/**
@@ -299,24 +299,6 @@
}

/**
- * Get the host timestamp policy from the supplied host element using the
- * value of a child element named 'policy'.
- * @param root the XML host element
- * @return the timestamp policy
- * @exception IOException if an IO related error occurs
- */
- private Policy getPolicy( Element root )
- throws IOException
- {
- Element element = ElementHelper.getChild( root, "policy" );
- if( null == element )
- {
- return Policy.FAST;
- }
- return Policy.createPolicy( ElementHelper.getValue( element ) );
- }
-
- /**
* Get the username from the supplied host element's credentials element
using the
* value of a child element named 'username'.
* @param root the XML host element
@@ -411,4 +393,18 @@
return ElementHelper.getValue( element );
}
}
+
+ private String getResolverClass( Element root )
+ throws IOException
+ {
+ Element element = ElementHelper.getChild( root, "resolver" );
+ if( null == element )
+ {
+ return "";
+ }
+ else
+ {
+ return ElementHelper.getValue( element );
+ }
+ }
}

Added:
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/ZipCache.java
==============================================================================
--- (empty file)
+++
development/main/transit/core/handler/src/main/net/dpml/transit/artifact/ZipCache.java
Thu Mar 24 18:03:30 2005
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2004 Stephen J. McConnell.
+ * Copyright 2004 Niclas Hedhman
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.dpml.transit.artifact;
+
+import java.util.HashMap;
+import java.util.Iterator;
+
+import java.util.zip.ZipFile;
+
+class ZipCache
+ implements Runnable
+{
+ private HashMap m_store;
+ private long m_timeToLive;
+ private Thread m_thread;
+
+ ZipCache()
+ {
+ m_store = new HashMap();
+ m_timeToLive = 30000;
+ }
+
+ ZipFile get( Artifact key )
+ {
+ synchronized( this ) // ensure no ConcurrentModificationException
can occur.
+ {
+ Entry entry = (Entry) m_store.get( key );
+ if( entry == null )
+ return null;
+ ZipFile zip = entry.m_file;
+ return zip;
+ }
+ }
+
+ void put( Artifact key, ZipFile file )
+ {
+ synchronized( this ) // ensure no ConcurrentModificationException
can occur.
+ {
+ Entry entry = new Entry( file );
+ m_store.put( key, entry );
+ if( m_thread == null )
+ {
+ m_thread = new Thread( this, "ZipCache-cleaner" );
+ m_thread.setDaemon( true );
+ m_thread.start();
+ }
+ }
+ }
+
+ public void run()
+ {
+ while( true )
+ {
+ try
+ {
+ synchronized( this )
+ {
+ long now = System.currentTimeMillis();
+ Iterator list = m_store.values().iterator();
+ while( list.hasNext() )
+ {
+ Entry entry = (Entry) list.next();
+ if( entry.m_collectTime < now )
+ {
+ entry.m_file.close();
+ list.remove();
+ }
+ }
+ if( m_store.size() == 0 )
+ {
+ m_thread = null;
+ break;
+ }
+ wait( 10000 );
+ }
+ } catch( Exception e )
+ {
+ // Can not happen?
+ // Just ignore and it will be handled in the next round.
+ e.printStackTrace();
+ }
+ }
+ }
+
+ class Entry
+ {
+ private ZipFile m_file;
+ private long m_collectTime;
+
+ Entry( ZipFile file )
+ {
+ m_file = file;
+ m_collectTime = System.currentTimeMillis() + m_timeToLive;
+ }
+
+ public boolean equals( Object obj )
+ {
+ if( obj == null )
+ return false;
+ if( obj.getClass().equals( Entry.class ) == false )
+ return false;
+ Entry other = (Entry) obj;
+
+ if( m_file.equals( other.m_file ) == false )
+ return false;
+
+ return true;
+ }
+
+ public int hashCode()
+ {
+ return m_file.hashCode();
+ }
+
+ public String toString()
+ {
+ return "Entry[" + m_file + ", " + m_collectTime + "]";
+ }
+ }
+}

Modified:
development/main/transit/core/handler/src/test/net/dpml/transit/artifact/OfflineTestCase.java
==============================================================================
---
development/main/transit/core/handler/src/test/net/dpml/transit/artifact/OfflineTestCase.java
(original)
+++
development/main/transit/core/handler/src/test/net/dpml/transit/artifact/OfflineTestCase.java
Thu Mar 24 18:03:30 2005
@@ -22,6 +22,7 @@
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.io.OutputStream;

import java.net.URL;
import java.net.URLClassLoader;
@@ -36,55 +37,108 @@
*/
public class OfflineTestCase extends TestCase
{
- protected void setUp() throws Exception
+ protected void setUp()
+ throws Exception
{
System.setProperty( "java.protocol.handler.pkgs", "net.dpml.transit"
);
System.setProperty( "dpml.transit.secured.disable", "true" );
System.setProperty( "dpml.transit.authority.file",
"target/test/test.authority" );
}

- public void testDownloadNoVersion() throws Exception
+ public void testDownloadNoVersion()
+ throws Exception
{
URL url = new URL( "artifact:testfile:dpml/test/1" );
String content = getContent( url );
assertEquals( "Content not retrieved.", "abc\n", content );
}

- public void testDownloadWithVersion() throws Exception
+ public void testDownloadWithVersion()
+ throws Exception
{
URL url = new URL( "artifact:testfile:dpml/test/abc#1.0.1" );
String content = getContent( url );
assertEquals( "Content not retrieved.", "abc\ndef\n", content );
}

- public void testClassLoader1() throws Exception
+ public void testClassLoader1()
+ throws Exception
{
URL url = new URL( "artifact:jar:dpml/test/dpml-test-testa" );
ClassLoader classloader = new URLClassLoader( new URL[]{ url } );
classloader.loadClass( "net.dpml.test.testa.A" );
}

- public void testClassLoader2() throws Exception
+ public void testClassLoader2()
+ throws Exception
{
URL url = new URL( "artifact:jar:dpml/test/dpml-test-testb" );
ClassLoader classloader = new URLClassLoader( new URL[]{ url } );
classloader.loadClass( "net.dpml.test.testb.B" );
}

- public void testContentConversionA() throws Exception
+ public void testContentConversionA()
+ throws Exception
{
URL url = new URL( "artifact:jar:dpml/test/dpml-test-testa" );
Object content = url.getContent();
assertTrue( "Content type not correct.", content instanceof
InputStream );
}

- public void testContentConversionB() throws Exception
+ public void testContentConversionB()
+ throws Exception
{
URL url = new URL( "artifact:png:dpml/test/sample" );
Object content = url.getContent();
assertTrue( "Content type not correct.", content instanceof
java.awt.image.ImageProducer );
}

+ public void testWriteExistingArtifact()
+ throws Exception
+ {
+ URL url = new URL( "artifact:png:dpml/test/sample" );
+ try
+ {
+ OutputStream out = url.openConnection().getOutputStream();
+ for( int i = 65 ; i < 91 ; i++ )
+ {
+ out.write( i );
+ }
+ out.write( 10 );
+ out.close();
+ fail( "Able to write to an existing artifact." );
+ } catch( java.io.IOException e )
+ {
+ // A "Artifact on server" exception should be thrown.
+ }
+ }
+
+ public void testWriteNewArtifact()
+ throws Exception
+ {
+ URL url = new URL( "artifact:txt:dpml/test/sample" );
+ OutputStream out = url.openConnection().getOutputStream();
+ for( int i = 65 ; i < 91 ; i++ )
+ {
+ out.write( i );
+ }
+ out.write( 10 );
+ out.close();
+
+ url = new URL( "artifact:txt:dpml/test/sample" );
+ InputStream in = url.openStream();
+ StringBuffer result = new StringBuffer();
+ while( true )
+ {
+ int value = in.read();
+ if( value == -1 )
+ break;
+ char ch = (char) value;
+ result.append( ch );
+ }
+ assertEquals( "ABCDEFGHIJKLMNOPQRSTUVWXYZ\n", result.toString() );
+ }
+
private String getContent( URL url )
throws Exception
{



  • svn commit: r2129 - in development/main: metro/composition/impl/src/main/net/dpml/composition/model/impl metro/composition/impl/src/test/net/dpml/composition/model/impl metro/composition/test/etc/test metro/composition/test/src/test/net/dpml/composition/model/impl/test metro/composition/test/src/test/net/dpml/composition/util transit/core/handler/src/main/net/dpml/transit transit/core/handler/src/main/net/dpml/transit/artifact transit/core/handler/src/test/net/dpml/transit/artifact, niclas, 03/24/2005

Archive powered by MHonArc 2.6.24.

Top of Page