001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: * $Header:$
018: */
019: package org.apache.beehive.controls.runtime.assembly;
020:
021: import org.apache.beehive.controls.api.bean.ControlImplementation;
022: import org.apache.beehive.controls.api.assembly.ControlAssemblyContext;
023: import org.apache.beehive.controls.api.assembly.ControlAssemblyException;
024: import org.apache.beehive.controls.api.assembly.ControlAssembler;
025: import org.apache.beehive.controls.api.assembly.DefaultControlAssembler;
026:
027: import java.io.File;
028: import java.io.IOException;
029: import java.util.Map;
030: import java.util.Set;
031:
032: /**
033: * Helper class to execute assembly logic.
034: */
035: public class Assembler {
036: /**
037: * Executes basic assembly algorithm. For each control type & impl specified, query each impl for the presence
038: * of an assembler -- for each assembler present, build the specified ControlAssemblyContext implementation,
039: * create an instance of the assembler and execute it.
040: *
041: * @param moduleRoot dir root of the module
042: * @param moduleName name of the module
043: * @param srcOutputRoot dir where assemblers can output source files
044: * @param factoryName name of the ControlAssemblyContext factory to use
045: * @param controlTypeToImpl map of control type name to control impl for all control types to be assembled in this module
046: * @param controlTypeToClients map of control type name to a set of control clients (in this module) that use this type
047: * @param cl classloader used to load factories and assemblers
048: * @throws ControlAssemblyException
049: * @throws IOException
050: */
051: public static void assemble(File moduleRoot, String moduleName,
052: File srcOutputRoot, String factoryName,
053: Map<String, String> controlTypeToImpl,
054: Map<String, Set<String>> controlTypeToClients,
055: ClassLoader cl) throws ControlAssemblyException,
056: IOException {
057: if (!moduleRoot.exists() || !srcOutputRoot.exists())
058: throw new IOException("Directories " + moduleRoot + " or "
059: + srcOutputRoot + " don't exist!");
060:
061: if (factoryName == null)
062: throw new ControlAssemblyException(
063: "Missing context factory names");
064:
065: if (cl == null)
066: throw new ControlAssemblyException(
067: "Must specify a classloader");
068:
069: ClassLoader origCL = Thread.currentThread()
070: .getContextClassLoader();
071: Thread.currentThread().setContextClassLoader(cl);
072:
073: try {
074: // Create the requested ControlAssemblyContext.Factory
075: Class factoryClass = cl.loadClass(factoryName);
076: ControlAssemblyContext.Factory factory = (ControlAssemblyContext.Factory) factoryClass
077: .newInstance();
078:
079: // Iterate over control types
080: Set<String> controlTypes = controlTypeToImpl.keySet();
081: for (String ct : controlTypes) {
082: // Search for applicable ControlAssemblers as specified on the control impls
083: String cImpl = controlTypeToImpl.get(ct);
084: Class cImplClass = cl.loadClass(cImpl);
085:
086: ControlImplementation a = (ControlImplementation) cImplClass
087: .getAnnotation(ControlImplementation.class);
088: if (a == null)
089: throw new ControlAssemblyException(
090: "Control implementation class="
091: + cImpl
092: + " missing ControlImplementation annotation");
093:
094: // For each non-default ControlAssembler, create one and call it.
095: Class<? extends ControlAssembler> assemblerClass = a
096: .assembler();
097: if (!assemblerClass
098: .equals(DefaultControlAssembler.class)) {
099: ControlAssembler assembler = assemblerClass
100: .newInstance();
101: Set<String> clients = controlTypeToClients.get(ct);
102: ControlAssemblyContext cac = factory.newInstance(cl
103: .loadClass(ct), null, clients, moduleRoot,
104: moduleName, srcOutputRoot);
105: assembler.assemble(cac);
106: }
107: }
108: } catch (ControlAssemblyException cae) {
109: // just rethrow ControlAssemblyExceptions, which will typically come from user-provided assemblers.
110: throw cae;
111: } catch (Throwable t) {
112: // Not expecting any throwables other than ControlAssemblyExceptions, so consider them as
113: // unexpected infrastructure issues and wrap them in a CAE.
114: throw new ControlAssemblyException(
115: "Assembly infrastructure exception", t);
116: } finally {
117: Thread.currentThread().setContextClassLoader(origCL);
118: }
119: }
120: }
|