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: package org.apache.cocoon.template.script;
018:
019: import java.lang.reflect.Constructor;
020: import java.util.HashMap;
021: import java.util.Map;
022: import java.util.Stack;
023:
024: import org.apache.avalon.framework.configuration.Configurable;
025: import org.apache.avalon.framework.configuration.Configuration;
026: import org.apache.avalon.framework.configuration.ConfigurationException;
027: import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
028: import org.apache.avalon.framework.logger.AbstractLogEnabled;
029: import org.apache.avalon.framework.service.ServiceException;
030: import org.apache.avalon.framework.service.ServiceManager;
031: import org.apache.avalon.framework.service.Serviceable;
032: import org.apache.avalon.framework.thread.ThreadSafe;
033: import org.apache.cocoon.template.environment.ParsingContext;
034: import org.apache.cocoon.template.instruction.Instruction;
035: import org.apache.cocoon.template.script.event.StartElement;
036: import org.apache.commons.lang.ClassUtils;
037: import org.apache.excalibur.source.Source;
038: import org.apache.excalibur.source.SourceResolver;
039: import org.xml.sax.Attributes;
040: import org.xml.sax.SAXException;
041: import org.xml.sax.SAXParseException;
042:
043: /**
044: * @version $Id: DefaultInstructionFactory.java 449189 2006-09-23 06:52:29Z crossley $
045: */
046: public class DefaultInstructionFactory extends AbstractLogEnabled
047: implements ThreadSafe, Serviceable, Configurable,
048: InstructionFactory {
049:
050: private final Map instructions = new HashMap();
051: private ServiceManager manager;
052: private final static Class[] INSTRUCTION_CONSTRUCTOR_PARAMS = new Class[] {
053: ParsingContext.class, StartElement.class, Attributes.class,
054: Stack.class };
055: private final static String CONFIG_LOCATION = "resource://org/apache/cocoon/template/template-instructions.xml";
056:
057: private void registerInstruction(String instructionName,
058: String targetNamespace, String className)
059: throws ConfigurationException {
060: Class clazz;
061: try {
062: clazz = Class.forName(className);
063: if (!ClassUtils.isAssignable(clazz, Instruction.class))
064: throw new ConfigurationException(
065: "Class '"
066: + className
067: + "' is not assignable to "
068: + "o.a.c.template.jxtg.script.event.StartInstruction ");
069: Constructor constructor = clazz
070: .getConstructor(INSTRUCTION_CONSTRUCTOR_PARAMS);
071:
072: String instructionKey = instructionKey(instructionName,
073: targetNamespace);
074: this .instructions.put(instructionKey, constructor);
075: } catch (Exception e) {
076: if (e instanceof ConfigurationException)
077: throw (ConfigurationException) e;
078: else
079: throw new ConfigurationException(
080: "unable to register instruction", e);
081: }
082: }
083:
084: private String instructionKey(String instructionName,
085: String targetNamespace) {
086: return "{" + targetNamespace + "}" + instructionName;
087: }
088:
089: private String instructionKey(StartElement element) {
090: return instructionKey(element.getLocalName(), element
091: .getNamespaceURI());
092: }
093:
094: public boolean isInstruction(StartElement element) {
095: String instructionKey = instructionKey(element);
096: return this .instructions.containsKey(instructionKey);
097: }
098:
099: public Instruction createInstruction(ParsingContext parsingContext,
100: StartElement startElement, Attributes attrs, Stack stack)
101: throws SAXException {
102: String instructionKey = instructionKey(startElement);
103: Constructor constructor = (Constructor) this .instructions
104: .get(instructionKey);
105: if (constructor == null)
106: throw new SAXParseException("unrecognized instruction: "
107: + instructionKey, startElement.getLocation(), null);
108: Object[] arguments = new Object[] { parsingContext,
109: startElement, attrs, stack };
110: try {
111: return (Instruction) constructor.newInstance(arguments);
112: } catch (Exception e) {
113: throw new SAXParseException("error creating instruction: "
114: + instructionKey, startElement.getLocation(), e);
115: }
116: }
117:
118: public void setupInstructions(Configuration conf)
119: throws ConfigurationException {
120: Configuration[] instructionSets = conf
121: .getChildren("instructions");
122: for (int i = 0; i < instructionSets.length; i++) {
123: Configuration instructionSet = instructionSets[i];
124: String namespace = instructionSet.getAttribute(
125: "targetNamespace", "");
126:
127: Configuration[] instr = instructionSet
128: .getChildren("instruction");
129: for (int j = 0; j < instr.length; j++) {
130: Configuration currentInstruction = instr[j];
131: String name = currentInstruction.getAttribute("name");
132: if (name == null)
133: throw new ConfigurationException(
134: "@name for instruction required");
135:
136: String className = currentInstruction
137: .getAttribute("class");
138: if (className == null)
139: throw new ConfigurationException(
140: "@class for instruction required");
141:
142: registerInstruction(name, namespace, className);
143: }
144: }
145: }
146:
147: /**
148: * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
149: */
150: public void service(ServiceManager manager) throws ServiceException {
151: this .manager = manager;
152: }
153:
154: /**
155: * @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
156: */
157: public void configure(Configuration omitted)
158: throws ConfigurationException {
159: SourceResolver resolver = null;
160: Source source = null;
161: try {
162: resolver = (SourceResolver) this .manager
163: .lookup(SourceResolver.ROLE);
164: source = resolver.resolveURI(CONFIG_LOCATION);
165: DefaultConfigurationBuilder configurationBuilder = new DefaultConfigurationBuilder();
166: Configuration conf = configurationBuilder.build(source
167: .getInputStream());
168: setupInstructions(conf);
169: } catch (Exception e) {
170: if (e instanceof ConfigurationException)
171: throw (ConfigurationException) e;
172: else
173: throw new ConfigurationException(
174: "unable to parse template instructions configuration",
175: e);
176: } finally {
177: if (source != null)
178: resolver.release(source);
179: if (resolver != null)
180: this.manager.release(resolver);
181: }
182: }
183: }
|