org.apache.beehive.controls.runtime.assembly.AssembleTask Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*
* $Header:$
*/
package org.apache.beehive.controls.runtime.assembly;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.TreeSet;
import java.net.URL;
import java.net.URLClassLoader;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.types.FileSet;
import org.apache.beehive.controls.runtime.generator.apt.ControlClientManifest;
import org.apache.beehive.controls.api.assembly.ControlAssemblyException;
/**
* AssembleTask defines a custom ant task to perform control assembly.
*
* The core assembly algorithm is documented and implemented in {@link Assembler}.
*
* Required attributes:
* moduleDir: path to the root of J2EE module on which to perform assembly.
* srcOutputDir: path to the dir where control assemblers may output source files.
* It may be necessary to run additional build steps in order to process such files (for example,
* if an assembler outputs Java source code, that code may need to be compiled).
* contextFactoryClassname: fully qualified classname of a factory class that implements
* {@link org.apache.beehive.controls.api.assembly.ControlAssemblyContext.Factory}. Typically this
* would depend on the type of module on which assembly is being run (EJB, webapp, etc). Different
* contexts will expose different APIs to control assemblers (making different descriptors available,
* etc).
*
* Supported nested elements:
* classpath: specifies the classpath that will be searched for control interfaces/implementations,
* control clients and control assemblers.
* fileset: specifies the control client manifests that should be processed by this assembly call.
*
* An example usage of the AssembleTask in an ant build script (build.xml):
*
*/
public class AssembleTask extends Task
{
public AssembleTask()
{
// do nothing
}
public void setContextFactoryClassName(String contextFactoryClassName)
{
_contextFactoryClassName = contextFactoryClassName;
}
public void setModuleDir( File moduleDir )
{
_moduleDir = moduleDir;
}
public void setModuleName( String moduleName )
{
_moduleName = moduleName;
}
public void setSrcOutputDir( File srcOutputDir )
{
_srcOutputDir = srcOutputDir;
}
public void setBindingFile(File bindingFile)
{
_bindingFile = bindingFile;
}
public FileSet createFileset()
{
_clientManifestFileSet = new FileSet();
return _clientManifestFileSet;
}
// used to set classpath as an attribute
public void setClasspath(Path classpath)
{
_classPath = new Path(getProject());
_classPath.append(classpath);
}
// used to set classpath as a nested element
public Path createClasspath()
{
_classPath = new Path(getProject());
return _classPath;
}
public void execute()
{
validateAttributeSettings();
if (_clientManifestFileSet == null)
{
log("No input fileset specified, nothing to do.");
return;
}
// get list of input files as list of ControlRefs files
File filesetDir = _clientManifestFileSet.getDir(getProject());
String[] clientManifests = _clientManifestFileSet.
getDirectoryScanner(getProject()).getIncludedFiles();
if (clientManifests.length == 0)
{
log("Input fileset contained no files, nothing to do.");
return;
}
List manifestFiles = new ArrayList();
for ( String mf : clientManifests )
{
File f = new File(filesetDir, mf );
if (!f.exists())
{
log("File " + f.getAbsolutePath() +
" in input fileset does not exist.");
continue;
}
manifestFiles.add(f);
}
// REVIEW: nested control usage is handled poorly right now.
// Need to refine how we pick up control client manifests, especially
// for manifests inside control jars (instead of blindly scanning and
// including all manifests inside all jars, should base it on actual nested
// control usage as analyzed by starting at non-control clients).
try
{
// Build map of control types to assemble by scanning supplied manifests
Map controlTypesToImpls = new HashMap();
Map> controlTypesToClients =
new HashMap>();
for ( File mf : manifestFiles )
{
ControlClientManifest ccmf = new ControlClientManifest( mf );
String controlClient = ccmf.getControlClient();
List controlTypes = ccmf.getControlTypes();
for ( String ct : controlTypes )
{
controlTypesToImpls.put( ct, ccmf.getDefaultImpl( ct ) );
Set clients = controlTypesToClients.get( ct );
if (clients == null)
{
clients = new TreeSet();
controlTypesToClients.put( ct, clients );
}
clients.add( controlClient );
}
}
// Build classloader to do loading
//
// TODO: The module dir should probably be in the classpath, since it seems reasonable
// for assemblers to want access to the classes in the module.
String[] classpaths = _classPath == null ? new String[0] : _classPath.list();
ClassLoader cl = buildClassLoader( classpaths, Assembler.class.getClassLoader() );
Assembler.assemble( _moduleDir, _moduleName, _srcOutputDir, _contextFactoryClassName,
controlTypesToImpls, controlTypesToClients, cl );
}
catch (Exception e)
{
e.printStackTrace();
throw new BuildException("Assembly failed.", e);
}
}
private void validateAttributeSettings() throws BuildException
{
if (_contextFactoryClassName == null)
throw new BuildException("The contextFactoryClassName attribute must be set");
if (_moduleDir == null)
throw new BuildException("The moduleDir attribute must be set");
if (_srcOutputDir == null)
throw new BuildException("The srcOutputDir attribute must be set");
}
private ClassLoader buildClassLoader( String[] paths, ClassLoader parentCL)
throws ControlAssemblyException
{
List list = new ArrayList();
for (int i=0; i