bloritsch 2003/03/18 09:11:09
Modified: fortress build.xml default.properties
Added: fortress/src/java/org/apache/avalon/fortress/impl/role
ServiceRoleManager.java
fortress/src/java/org/apache/avalon/fortress/util
Service.java
fortress/src/tools/org/apache/avalon/fortress/tools
ComponentMetaInfoCollector.java
LoaderGenerator.java ServiceCollector.java
Log:
add support for build time collection of roles and implementations--changes will
come when we standardize on names
Revision Changes Path
1.78 +43 -13 avalon-excalibur/fortress/build.xml
Index: build.xml
===================================================================
RCS file: /home/cvs/avalon-excalibur/fortress/build.xml,v
retrieving revision 1.77
retrieving revision 1.78
diff -u -r1.77 -r1.78
--- build.xml 12 Mar 2003 13:23:50 -0000 1.77
+++ build.xml 18 Mar 2003 17:11:09 -0000 1.78
@@ -16,7 +16,8 @@
<pathelement location="${avalon-logkit.jar}"/> <!-- deprecated -->
<pathelement location="${logkit.jar}"/>
<pathelement location="${commons-collections.jar}"/>
- <pathelement location="${util.concurrent.jar}"/>
+ <pathelement location="${util.concurrent.jar}"/>
+ <pathelement location="${qdox.jar}"/>
<pathelement location="${excalibur-instrument.jar}"/>
<pathelement location="${excalibur-instrument-manager.jar}"/>
<pathelement location="${excalibur-instrument-manager-interfaces.jar}"/>
@@ -170,18 +171,6 @@
<exclude name="**/*Assembly*.java" unless="include.meta"/>
</javac>
- <javac srcdir="src/ng"
- destdir="${build.classes}"
- debug="${build.debug}"
- optimize="${build.optimize}"
- deprecation="${build.deprecation}"
- target="1.2">
- <classpath refid="build.path"/>
- <include name="**/*.java"/>
- <exclude name="**/util/*.java" unless="include.meta"/>
- <exclude name="**/container/**/*.java" unless="include.meta"/>
- </javac>
-
<!-- copy resources to same location as .class files -->
<copy todir="${build.classes}">
<fileset dir="${java.dir}">
@@ -192,6 +181,23 @@
</target>
+ <target name="compile-tools" depends="compile">
+
+ <mkdir dir="${build.dir}/tools"/>
+
+ <javac srcdir="src/tools"
+ destdir="${build.dir}/tools"
+ debug="${build.debug}"
+ optimize="${build.optimize}"
+ deprecation="${build.deprecation}"
+ target="1.2">
+ <classpath>
+ <path refid="build.path"/>
+ <pathelement location="${build.classes}"/>
+ </classpath>
+ </javac>
+ </target>
+
<!-- Compiles the unit test source code -->
<target name="compile-test" depends="compile,dependencies-test,path-builder"
description="Compiles the source code">
<mkdir dir="${build.testsrc}"/>
@@ -237,6 +243,30 @@
</filterset>
</copy>
+ </target>
+
+ <target name="tools-jar" depends="compile-tools, jar" description="Generates
the ANT task tool jar">
+ <mkdir dir="${build.lib}"/>
+
+ <jar jarfile="${build.lib}/${tools.jar.name}"
+ basedir="${build.dir}/tools"
+ compress="${build.compress}">
+ <manifest>
+ <attribute name="Extension-Name" value="${name}-tools"/>
+ <attribute name="Specification-Vendor" value="Apache Software
Foundation"/>
+ <attribute name="Specification-Version" value="1.0"/>
+ <attribute name="Implementation-Vendor" value="Apache Software
Foundation"/>
+ <attribute name="Implementation-Version" value="${package-version}"/>
+ </manifest>
+ <exclude name="**/test/**"/>
+ <zipfileset dir="${build.conf}" prefix="META-INF/">
+ <include name="LICENSE.txt"/>
+ </zipfileset>
+ <fileset dir="${build.classes}">
+ <include name="**/util/Service*"/>
+ <include name="**/role/Service*"/>
+ </fileset>
+ </jar>
</target>
<!-- Creates all the .jar file -->
1.68 +6 -0 avalon-excalibur/fortress/default.properties
Index: default.properties
===================================================================
RCS file: /home/cvs/avalon-excalibur/fortress/default.properties,v
retrieving revision 1.67
retrieving revision 1.68
diff -u -r1.67 -r1.68
--- default.properties 11 Mar 2003 15:15:23 -0000 1.67
+++ default.properties 18 Mar 2003 17:11:09 -0000 1.68
@@ -19,6 +19,9 @@
# ----- Doug Lea's Concurrent Utils, version 1.3 or later -----
util.concurrent.jar=${basedir}/../event/lib/util.concurrent-1.3.1.jar
+# ----- QDox Jar ----
+qdox.jar=${basedir}/../lib/qdox-1.1.jar
+
# ----- Excalibur Lifecycle -----
excalibur-lifecycle.home=${basedir}/../lifecycle
excalibur-lifecycle.lib=${excalibur-lifecycle.home}/build/lib
@@ -165,6 +168,9 @@
# name of jar file
jar.name = ${name}-${version}.jar
+
+# name of tools jar file
+tools.jar.name = ${name}-tools-${version}.jar
# property indicating directory where all distribution archives are placed
dist.base = distributions
1.1
avalon-excalibur/fortress/src/java/org/apache/avalon/fortress/impl/role/ServiceRoleManager.java
Index: ServiceRoleManager.java
===================================================================
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software
* itself, if and wherever such third-party acknowledgments
* normally appear.
*
* 4. The names "D-Haven" and "Apache Software Foundation"
* must not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact [EMAIL PROTECTED]
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.avalon.fortress.impl.role;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.avalon.fortress.RoleManager;
import org.apache.avalon.fortress.impl.handler.PerThreadComponentHandler;
import org.apache.avalon.fortress.impl.handler.PoolableComponentHandler;
import org.apache.avalon.fortress.impl.handler.ThreadSafeComponentHandler;
import org.apache.avalon.fortress.util.Service;
import org.apache.avalon.framework.activity.Initializable;
/**
* ServiceRoleManager follows some simple rules to dynamically gather all
* services and the meta-information into one role manager. This really gets
* rid of the need of multiple role managers. It uses a set of entries in your
* JARs to do its magic.
*
* <p><code><b>/services.list</b></code></p>
*
* <p>
* This lists all the services that are <em>defined</em> in this jar.
* </p>
*
* <p><code><b>/META-INF/services/</b><i>my.class.Name</i></code></p>
*
* <p>
* One entry for each service where there are implementations for a role. This
* follows the JAR services mechanism.
* </p>
*
* <p><code><i>/my/class/Implementation.meta</i></code></p>
*
* <p>
* There is one entry sitting right beside every implementation class. This
* holds all the meta information for the associated class. It is a simple
* properties file.
* </p>
*
* <h3>ANT Tasks available</h3>
* <p>
* We have a couple of ANT tasks to make this really easy. If you add this
* to your ANT build script (customizing it to make it work in your environment),
* it will make your life alot easier:
* </p>
*
* <pre>
* <taskdef name="collect-metainfo"
classname="org.d_haven.guiapp.tools.ComponentMetaInfoCollector">
* <classpath>
* <path refid="project.class.path"/>
* <pathelement path="${tools.dir}/guiapp-tools.jar"/>
* </classpath>
* </taskdef>
*
* <taskdef name="collect-services"
classname="org.d_haven.guiapp.tools.ServiceCollector">
* <classpath>
* <path refid="project.class.path"/>
* <pathelement path="${tools.dir}/guiapp-tools.jar"/>
* </classpath>
* </taskdef>
*
* <collect-metainfo destdir="${build.classes}">
* <fileset dir="${src.dir}"/>
* </collect-metainfo>
*
* <collect-services inputjar="${build.dir}/${name}-core.jar"
* outputjar="${lib.dir}/${name}.jar"/>
* </pre>
*
* @author <a href="mailto:[EMAIL PROTECTED]">Berin Loritsch</a>
*/
public class ServiceRoleManager extends AbstractRoleManager implements Initializable
{
/** Translate from scope to component handler */
private static final Map m_scopeMap;
/** Used to split words in class names */
private static final Pattern upperCase = Pattern.compile("([A-Z]+)");
// Initialize the scope map
static
{
Map scopes = new HashMap();
scopes.put("container", ThreadSafeComponentHandler.class.getName());
scopes.put("thread", PerThreadComponentHandler.class.getName());
scopes.put("request", PoolableComponentHandler.class.getName());
m_scopeMap = Collections.unmodifiableMap(scopes);
}
/**
* Create a ServiceRoleManager.
*/
public ServiceRoleManager()
{
super(null);
}
/**
* Create a ServiceRoleManager with a parent RoleManager.
*
* @param parent
*/
public ServiceRoleManager(RoleManager parent)
{
super(parent, null);
}
/**
* Create a ServiceRoleManager with the supplied classloader and
* parent RoleManager.
*
* @param parent
* @param loader
*/
public ServiceRoleManager(RoleManager parent, ClassLoader loader)
{
super(parent, loader);
}
/**
* Convert a Component implmentation classname into a shorthand
* name. It assumes all classnames for a particular component is
* unique.
*
* @param string The classname of a component
* @return String the short name
*/
public static final String createShortName(String className)
{
Matcher matcher =
upperCase.matcher(className.substring(className.lastIndexOf('.') + 1));
StringBuffer shortName = new StringBuffer();
while (matcher.find())
{
if ( shortName.length() == 0 )
{
matcher.appendReplacement(shortName, "$1");;
}
else
{
matcher.appendReplacement(shortName, "-$1");
}
}
matcher.appendTail(shortName);
return shortName.toString().toLowerCase();
}
/**
* Initialize the ServiceRoleManager by looking at all the services and
* classes available in the system.
*/
public void initialize() throws Exception
{
Set services = new HashSet();
Enumeration enum = getLoader().getResources("services.list");
while (enum.hasMoreElements())
{
readEntries(services, (URL)enum.nextElement());
}
Iterator it = services.iterator();
while (it.hasNext())
{
String role = (String)it.next();
getLogger().debug("Adding service: " + role);
setupImplementations(role);
}
}
/**
* Get all the implementations of a service and set up their meta
* information.
*
* @param role
*/
private void setupImplementations(String role)
throws IOException, ClassNotFoundException
{
Iterator it = Service.providers(getLoader().loadClass(role));
while (it.hasNext())
{
String impl = ((Class)it.next()).getName();
getLogger().debug("Reading meta info for " + impl);
readMeta(role, impl);
}
}
/**
* Read the meta information in and actually add the role.
*
* @param role
* @param implementation
*/
private void readMeta(String role, String implementation)
{
Properties meta = new Properties();
try
{
meta.load(getLoader().getResourceAsStream(translate(implementation)));
}
catch (IOException ioe)
{
getLogger().error("Could not load meta information for " +
implementation + ", skipping this class.");
return;
}
String shortName = meta.getProperty("avalon.configname",
createShortName(implementation));
String handler = getHandler(meta);
addRole(shortName, role, implementation, handler);
}
/**
* Get the name of the requested component handler.
*
* @param meta
* @return String
*/
private String getHandler(Properties meta)
{
String scope = meta.getProperty("avalon.scope", null);
String handler = null;
if (null != scope)
{
handler = (String)m_scopeMap.get(scope);
}
else
{
handler = meta.getProperty("fortress.handler");
}
if (null == handler)
{
handler = PerThreadComponentHandler.class.getName();
}
return handler;
}
/**
* Translate a class name into the meta file name.
*
* @param implementation
* @return String
*/
private String translate(String implementation)
{
String entry = implementation.replace('.', '/');
entry += ".meta";
return entry;
}
/**
* Read entries in a list file and add them all to the provided Set.
*
* @param services
* @param url
*/
private void readEntries(Set entries, URL url)
throws IOException
{
BufferedReader reader = new BufferedReader( new
InputStreamReader(url.openStream()) );
String entry = reader.readLine();
while (entry != null)
{
entries.add(entry);
entry = reader.readLine();
}
reader.close();
}
}
1.1
avalon-excalibur/fortress/src/java/org/apache/avalon/fortress/util/Service.java
Index: Service.java
===================================================================
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software
* itself, if and wherever such third-party acknowledgments
* normally appear.
*
* 4. The names "D-Haven" and "Apache Software Foundation"
* must not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact [EMAIL PROTECTED]
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.avalon.fortress.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import javax.swing.ImageIcon;
/**
* This class handles looking up service providers on the class path.
* It implements the system described in:
*
* <a href="http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html#Service Provider">
* File Specification Under Service Provider</a>. Note that this interface is
* very similar to the one they describe whiehc seems to be missing in the JDK.
*
* This class adapted from <code>org.apache.batik.util.Service</code>
*
* @author <a href="[EMAIL PROTECTED]">Berin Loritsch</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Thomas DeWeese</a>
* @version 1.0
*/
public final class Service
{
private static String SERVICES = "META-INF/services/";
private static HashMap providers = new HashMap();
/**
* Private constructor to keep from instantiating this class
*/
private Service()
{}
/**
* Get all the providers for the specified services.
*
* @param klass the interface <code>Class</code>
*
* @return an <code>Iterator</code> for the providers.
*/
public static synchronized Iterator providers( Class klass )
{
String serviceFile = SERVICES + klass.getName();
ClassLoader loader = Thread.currentThread().getContextClassLoader();
if( null == loader )
{
loader = klass.getClassLoader();
}
Set providerSet = ( Set )providers.get( serviceFile );
if( null == providerSet )
{
providerSet = new HashSet();
Enumeration enum = null;
boolean errorOccurred = false;
providers.put( serviceFile, providerSet );
try
{
enum = loader.getResources( serviceFile );
}
catch( IOException ioe )
{
errorOccurred = true;
}
if( !errorOccurred )
{
while( enum.hasMoreElements() )
{
try
{
URL url = ( URL )enum.nextElement();
InputStream is = url.openStream();
BufferedReader reader = new BufferedReader(
new InputStreamReader( is,
"UTF-8" ) );
String line = reader.readLine();
while( null != line )
{
try
{
int comment = line.indexOf( '#' );
if( comment > -1 )
{
line = line.substring( 0, comment );
}
line.trim();
if( line.length() > 0 )
{
// We just want the types, not the instances
providerSet.add( loader.loadClass( line ) );
}
}
catch( Exception e )
{
// try the next line
}
line = reader.readLine();
}
}
catch( Exception e )
{
// try the next file
}
}
}
}
return providerSet.iterator();
}
/**
* Load an icon from the JARs
*
* @param entry Path to the icon
* @return ImageIcon The ImageIcon from the loaded icon.
*/
public static ImageIcon loadLibraryIcon( String entry )
{
ClassLoader loader = Thread.currentThread().getContextClassLoader();
return new ImageIcon( loader.getResource( entry ) );
}
}
1.1
avalon-excalibur/fortress/src/tools/org/apache/avalon/fortress/tools/ComponentMetaInfoCollector.java
Index: ComponentMetaInfoCollector.java
===================================================================
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software
* itself, if and wherever such third-party acknowledgments
* normally appear.
*
* 4. The names "D-Haven" and "Apache Software Foundation"
* must not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact [EMAIL PROTECTED]
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.avalon.fortress.tools;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
import org.apache.avalon.fortress.impl.handler.FactoryComponentHandler;
import org.apache.avalon.fortress.impl.handler.PerThreadComponentHandler;
import org.apache.avalon.fortress.impl.handler.PoolableComponentHandler;
import org.apache.avalon.fortress.impl.handler.ThreadSafeComponentHandler;
import org.apache.avalon.fortress.impl.role.ServiceRoleManager;
import org.apache.avalon.framework.thread.SingleThreaded;
import org.apache.avalon.framework.thread.ThreadSafe;
import org.apache.tools.ant.BuildException;
import com.thoughtworks.qdox.ant.AbstractQdoxTask;
import com.thoughtworks.qdox.model.DocletTag;
import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.Type;
/**
* @author bloritsch
*
* To change this generated comment go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
public class ComponentMetaInfoCollector extends AbstractQdoxTask
{
/**
* The services to write the meta info for.
*/
private Set m_services = new HashSet();
/**
* The destination directory for metadata files.
*/
private File m_destDir;
/**
* The service list destination.
*/
private File m_serviceFile;
public void setDestDir( final File destDir )
{
m_destDir = destDir;
}
/**
* Execute generator task.
*/
public void execute()
throws BuildException
{
validate();
final String message =
"Writing Info descriptors as property files (.meta).";
log( message );
super.execute();
try
{
writeInfoMetaData();
PrintWriter writer = new PrintWriter( new FileWriter( m_serviceFile ) );
Iterator it = m_services.iterator();
while (it.hasNext())
{
writer.println(it.next());
}
writer.close();
}
catch( final Exception e )
{
throw new BuildException( e.toString(), e );
}
}
/**
* Validate that the parameters are valid.
*/
private void validate()
{
if( null == m_destDir )
{
final String message =
"DestDir (" + m_destDir + ") not specified";
throw new BuildException( message );
}
if( !m_destDir.isDirectory() )
{
final String message =
"DestDir (" + m_destDir + ") is not a directory.";
throw new BuildException( message );
}
if( !m_destDir.exists() && !m_destDir.mkdirs() )
{
final String message =
"DestDir (" + m_destDir + ") could not be created.";
throw new BuildException( message );
}
m_serviceFile = new File(m_destDir, "services.list");
}
/**
* Output the metadata files.
*
* @throws IOException If a problem writing output
*/
private void writeInfoMetaData() throws IOException
{
final Iterator it = allClasses.iterator();
while( it.hasNext() )
{
final JavaClass javaClass = (JavaClass)it.next();
DocletTag tag = javaClass.getTagByName( "avalon.service" );
if( null != tag )
{
m_services.add(javaClass.getFullyQualifiedName());
}
else
{
tag = javaClass.getTagByName( "avalon.component" );
if( null != tag )
{
Properties meta = new Properties();
prepareMetaInfo(meta, javaClass);
File metaFile =
getOutputFileForClass(javaClass.getFullyQualifiedName());
FileOutputStream fos = new FileOutputStream(metaFile);
meta.store(fos, "Meta-Information for " +
javaClass.getFullyQualifiedName());
}
}
}
}
/**
* @param meta
* @param javaClass
*/
private void prepareMetaInfo(Properties meta, JavaClass javaClass)
{
DocletTag avalonScope = javaClass.getTagByName("avalon.scope");
DocletTag fortressHandler = javaClass.getTagByName("fortress.handler");
String scope = null;
String handler = null;
if ( avalonScope == null && fortressHandler == null )
{
Type[] interfaces = javaClass.getImplements();
for (int i = 0; i < interfaces.length && handler != null; i++)
{
if(interfaces[i].getClass().equals(ThreadSafe.class))
{
handler = ThreadSafeComponentHandler.class.getName();
}
else if
(interfaces[i].getClass().getName().equals("org.apache.avalon.excalibur.pool.Poolable")
||
interfaces[i].getClass().getName().equals("org.apache.avalon.excalibur.pool.Recyclable"))
{
handler = PoolableComponentHandler.class.getName();
}
else if (interfaces[i].getClass().equals(SingleThreaded.class))
{
handler = FactoryComponentHandler.class.getName();
}
}
}
if (null != avalonScope)
{
scope = avalonScope.getValue();
}
else if (handler != null)
{
handler = (null == fortressHandler) ?
PerThreadComponentHandler.class.getName() : fortressHandler.getValue();
}
if ( null != scope ) meta.setProperty("avalon.scope", scope);
if ( null != handler ) meta.setProperty("fortress.handler", handler);
DocletTag avalonConfigName = javaClass.getTagByName("avalon.configname");
if ( null == avalonConfigName ) avalonConfigName =
javaClass.getTagByName("fortress.configname");
meta.setProperty("avalon.configname", (avalonConfigName == null) ?
ServiceRoleManager.createShortName(javaClass.getName()) : avalonConfigName.getValue()
);
}
/**
* Determine the file for specified [EMAIL PROTECTED] ComponentInfo}.
*
* @param classname the fully qualified name of file to generate
* @return the file for info
* @throws IOException if unable to determine base file
*/
private File getOutputFileForClass( final String classname )
throws IOException
{
String filename =
classname.replace( '.', File.separatorChar );
filename += ".meta";
return new File( m_destDir, filename ).getCanonicalFile();
}
}
1.1
avalon-excalibur/fortress/src/tools/org/apache/avalon/fortress/tools/LoaderGenerator.java
Index: LoaderGenerator.java
===================================================================
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software
* itself, if and wherever such third-party acknowledgments
* normally appear.
*
* 4. The names "D-Haven" and "Apache Software Foundation"
* must not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact [EMAIL PROTECTED]
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.avalon.fortress.tools;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.taskdefs.Jar;
import org.apache.tools.ant.taskdefs.Manifest;
import org.apache.tools.ant.types.ZipFileSet;
/**
* Creates a Loader archive.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Berin Loritsch</a>
*/
public class LoaderGenerator
extends Jar
{
private File m_splashScreen;
private File m_buildNumber;
private String m_name;
private String m_version;
private String m_lookAndFeel;
private String m_proxy;
public LoaderGenerator()
{
archiveType = "jar";
emptyBehavior = "fail";
}
public void setDest( final File file )
{
setDestFile( file );
}
public void setSplashScreen( final File screen )
{
m_splashScreen = screen;
if( !m_splashScreen.exists() )
{
final String message =
"Splash Screen: " + m_splashScreen + " does not exist.";
throw new BuildException( message, getLocation() );
}
if( !m_splashScreen.isFile() )
{
final String message =
"Splash Screen: " + m_splashScreen + " is not a file.";
throw new BuildException( message, getLocation() );
}
}
public void setBuildNumberFile( final File buildNumber )
{
m_buildNumber = buildNumber;
if( !m_buildNumber.exists() )
{
final String message =
"Build Number File: " + m_buildNumber + " does not exist.";
throw new BuildException( message, getLocation() );
}
if( !m_buildNumber.isFile() )
{
final String message =
"Build Number File: " + m_buildNumber + " is not a file.";
throw new BuildException( message, getLocation() );
}
}
public void setAppName( final String appName )
{
m_name = appName;
if( null == m_name || m_name.length() == 0 )
{
final String message =
"Application Name must be set.";
throw new BuildException( message, getLocation() );
}
}
public void setVersion( final String version )
{
m_version = version;
if( null == m_version || m_version.length() == 0 )
{
final String message = "Application Version must be supplied.";
throw new BuildException( message, getLocation() );
}
}
public void setLookAndFeel( final String laf )
{
m_lookAndFeel = laf;
if( null == m_lookAndFeel || m_lookAndFeel.length() == 0 )
{
final String message = "Look and Feel must be supplied.";
throw new BuildException( message, getLocation() );
}
}
public void setProxy( final String proxyClassName )
{
m_proxy = proxyClassName;
if( null == m_proxy || m_proxy.length() == 0 )
{
final String message = "Application Proxy class name must be supplied.";
throw new BuildException( message, getLocation() );
}
log("Warning, you are overriding the default application proxy class.");
}
public void execute()
throws BuildException
{
if( null == m_splashScreen )
{
final String message = "splashscreen attribute is required";
throw new BuildException( message, getLocation() );
}
if( null == m_name )
{
final String message = "name attribute is required";
throw new BuildException( message, getLocation() );
}
if( null == m_version )
{
final String message = "version attribute is required";
throw new BuildException( message, getLocation() );
}
if( null == m_proxy )
{
m_proxy = "org.d_haven.guiapp.container.FortressRunner";
}
if ( null == m_lookAndFeel )
{
m_lookAndFeel = "system";
}
File propFile = null;
try
{
Properties props = new Properties();
String build = "0";
if (null != m_buildNumber)
{
FileInputStream bfis = new FileInputStream(m_buildNumber);
Properties buildProps = new Properties();
buildProps.load(bfis);
bfis.close();
build = buildProps.getProperty("build.number");
}
props.put("app.name", m_name);
props.put("app.version", m_version);
props.put("app.build", build);
props.put("app.laf", m_lookAndFeel);
props.put("app.proxy", m_proxy);
propFile = File.createTempFile("app", ".properties");
propFile.deleteOnExit();
FileOutputStream pos = new FileOutputStream(propFile);
props.store(pos, "#Application constants");
pos.close();
Manifest manifest = Manifest.getDefaultManifest();
Manifest.Attribute attr = new Manifest.Attribute();
attr.setName("Main-Class");
attr.setValue("org.d_haven.guiapp.Main");
manifest.addConfiguredAttribute(attr);
addConfiguredManifest(manifest);
mergeArchive();
}
catch (Exception e)
{
e.printStackTrace();
throw new BuildException("Could not create properties", getLocation());
}
pushFile( "META-INF/app.properties", propFile );
pushFile( "org/d_haven/guiapp/splashscreen.jpg", m_splashScreen);
super.execute();
}
private void mergeArchive()
throws IOException
{
File loaderJar = File.createTempFile("loader", ".jar");
loaderJar.deleteOnExit();
InputStream resourceJar =
getClass().getClassLoader().getResourceAsStream("loader.jar");
FileOutputStream fos = new FileOutputStream(loaderJar);
int length = -1;
byte[] buffer = new byte[1024];
while ( (length = resourceJar.read(buffer)) > 0 )
{
fos.write(buffer,0,length);
}
resourceJar.close();
fos.close();
final ZipFileSet zipFileSet = new ZipFileSet();
zipFileSet.setSrc(loaderJar);
zipFileSet.setIncludes("org/**");
addFileset(zipFileSet);
}
private void pushFile( final String path, final File file )
{
final ZipFileSet zipFileSet = new ZipFileSet();
zipFileSet.setDir( new File( file.getParent() ) );
zipFileSet.setIncludes( file.getName() );
zipFileSet.setFullpath( path );
super.addFileset( zipFileSet );
}
protected void cleanUp()
{
super.cleanUp();
m_splashScreen = null;
m_name = null;
m_version = null;
m_lookAndFeel = null;
m_proxy = null;
}
}
1.1
avalon-excalibur/fortress/src/tools/org/apache/avalon/fortress/tools/ServiceCollector.java
Index: ServiceCollector.java
===================================================================
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software
* itself, if and wherever such third-party acknowledgments
* normally appear.
*
* 4. The names "D-Haven" and "Apache Software Foundation"
* must not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact [EMAIL PROTECTED]
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.avalon.fortress.tools;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task;
/**
* Look at all the classes in a JAR file and determine if they
* implement a specified service. When we are done, serialize the
* list to the appropriate services file.
*
* @author <a href="bloritsch.at.apache.org">Berin Loritsch</a>
*/
public class ServiceCollector extends Task
{
private File m_serviceList;
private Map m_serviceMap;
private final Set m_services = new HashSet();
private File m_inJar = null;
private File m_outJar = null;
/**
* Add elements of the form:
*
* <service name="org.apache.package.MyInterface/>
*
* @param service The ServiceElement to add
*/
public void addConfiguredService(ServiceElement service)
{
String serviceName = service.getName();
if (null == serviceName || "".equals(serviceName.trim()))
{
String message = "Must supply a Service Name";
throw new BuildException(message, getLocation());
}
m_services.add(serviceName);
}
/**
* Support the attribute "inputjar".
*
* @param input The File representing a JAR file.
*/
public void setInputJar(File input)
{
if ( null == input || input.isDirectory() )
{
String message = "Jar attribute is not a file";
throw new BuildException(message, getLocation());
}
m_inJar = input;
}
/**
* Support the attribute "outputjar".
*
* @param input The File representing a JAR file.
*/
public void setOutputJar(File output)
{
if ( null == output || output.isDirectory() )
{
String message = "Jar attribute is not a file";
throw new BuildException(message, getLocation());
}
m_outJar = output;
}
public void setServiceList(File serviceList)
{
if ( null == serviceList || serviceList.isDirectory() )
{
String message = "ServiceList attribute is not a file";
throw new BuildException(message, getLocation());
}
m_serviceList = serviceList;
}
/**
* Perform the actual checks to extract services.
*/
public void execute()
{
if ( m_inJar == null )
{
throw new BuildException("Input Jar Attribute must be set",
getLocation());
}
if ( m_outJar == null )
{
throw new BuildException("Output Jar Attribute must be set",
getLocation());
}
if ( m_inJar.getAbsolutePath().equals(m_outJar.getAbsolutePath()))
{
throw new BuildException("The two jars cannot be the same.",
getLocation());
}
log("Collecting Services", Project.MSG_INFO);
try
{
URLClassLoader loader = new URLClassLoader(new URL[]{m_inJar.toURL()},
getClass().getClassLoader());
FileOutputStream out = new FileOutputStream(m_outJar);
try
{
Enumeration enum = loader.getResources("services.list");
while (enum.hasMoreElements())
{
URL resource = (URL)enum.nextElement();
BufferedReader reader = new BufferedReader(new
InputStreamReader(resource.openStream()));
readServiceList(reader);
reader.close();
}
}
catch (IOException ioe)
{
throw new BuildException(ioe);
}
if ( m_serviceList != null )
{
BufferedReader reader;
try
{
reader = new BufferedReader(new FileReader(m_serviceList));
readServiceList(reader);
reader.close();
}
catch (FileNotFoundException fnfe)
{
throw new BuildException(fnfe);
}
catch (IOException ioe)
{
throw new BuildException(ioe);
}
}
if ( m_services.isEmpty() )
{
log("No services selected.", Project.MSG_WARN);
}
JarFile jarFile = new JarFile(m_inJar);
JarOutputStream outJar = new JarOutputStream(out, jarFile.getManifest());
m_serviceMap = new HashMap();
Iterator it = m_services.iterator();
while(it.hasNext())
{
String name = it.next().toString();
try
{
Class klass = loader.loadClass(name);
if ( klass.isInterface() )
{
m_serviceMap.put(klass, new LinkedList());
}
}
catch(Exception e)
{
log(name + " is not an interface", Project.MSG_WARN);
}
}
Enumeration entries = jarFile.entries();
while (entries.hasMoreElements())
{
JarEntry entry = (JarEntry)entries.nextElement();
String name = entry.getName();
if (name.endsWith(".class"))
{
try
{
String className = name.substring(0, name.length() -
".class".length()).replace('/', '.');
Class klass = loader.loadClass(className);
checkClass(klass);
}
catch (Exception e)
{
log(e.getMessage(), Project.MSG_VERBOSE);
}
}
if ( ! "META-INF/MANIFEST.MF".equals(name) )
{
if ("services.list".equals(name))
{
entry = new JarEntry("services.list");
outJar.putNextEntry(entry);
Iterator services = m_services.iterator();
while (services.hasNext())
{
String service = (String)services.next();
service += "\n";
outJar.write(service.getBytes());
}
}
else
{
outJar.putNextEntry(entry);
InputStream entryStream = jarFile.getInputStream(entry);
int length = -1;
byte[] buffer = new byte[1024];
// Read the entry and write it to the temp jar.
while ((length = entryStream.read(buffer)) != -1)
{
outJar.write(buffer, 0, length);
}
}
}
}
it = m_serviceMap.keySet().iterator();
while (it.hasNext())
{
Class iface = (Class)it.next();
String name = iface.getName();
JarEntry entry = new JarEntry("META-INF/services/" + name);
outJar.putNextEntry(entry);
List impls = (List)m_serviceMap.get(iface);
Iterator imit = impls.iterator();
while(imit.hasNext())
{
String implementation = ((Class)imit.next()).getName();
implementation += "\n";
outJar.write(implementation.getBytes());
}
}
outJar.close();
jarFile.close();
m_inJar.deleteOnExit();
log("Deleting the input jar", Project.MSG_INFO);
}
catch (Exception e)
{
e.printStackTrace();
throw new BuildException("Could not process JAR: " + m_inJar.getName());
}
}
public void readServiceList(BufferedReader reader) throws IOException
{
String line = reader.readLine();
while ( line != null )
{
m_services.add(line);
line = reader.readLine();
}
}
/**
* The core of the checkClass() logic. It validates the
* class passed in against the set of interfaces we have.
*
* @param klass
*/
protected void checkClass(Class klass)
{
if ( ! klass.isInterface() )
{
if ( ! Modifier.isAbstract(klass.getModifiers()) )
{
Iterator it = m_serviceMap.keySet().iterator();
while (it.hasNext())
{
Class iface = (Class) it.next();
if ( iface.isAssignableFrom(klass) )
{
log(klass.getName() + " implements " + iface.getName(),
Project.MSG_VERBOSE);
List list = (List) m_serviceMap.get(iface);
list.add(klass);
}
}
}
}
}
/**
* Clean up after ourselves so we can reuse this.
*/
protected void cleanUp()
{
m_services.clear();
m_serviceMap.clear();
m_inJar = null;
m_outJar = null;
}
/**
* The ServiceElement that is used to handle the
* <service name="foo"/> nested elements.
*/
public static class ServiceElement
{
private String _name = "";
/**
* Get the name of the service.
*
* @return String
*/
public String getName()
{
return _name;
}
/**
* Sets the name of the service.
* @param name
*/
public void setName(String name)
{
_name = name;
}
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]