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.components.source.impl;
018:
019: import org.apache.avalon.framework.component.ComponentManager;
020: import org.apache.cocoon.ProcessingException;
021: import org.apache.cocoon.components.source.SourceUtil;
022: import org.apache.cocoon.environment.Environment;
023: import org.apache.cocoon.environment.ModifiableSource;
024: import org.apache.excalibur.source.Source;
025: import org.apache.excalibur.source.SourceException;
026: import org.apache.excalibur.source.SourceResolver;
027: import org.xml.sax.ContentHandler;
028: import org.xml.sax.InputSource;
029: import org.xml.sax.SAXException;
030:
031: import java.io.IOException;
032: import java.io.InputStream;
033: import java.lang.reflect.InvocationHandler;
034: import java.lang.reflect.InvocationTargetException;
035: import java.lang.reflect.Method;
036: import java.lang.reflect.Proxy;
037:
038: /**
039: * An <code>InvocationHandler</code> which acts as a proxy for excalibur
040: * <code>Source</code> objects to make them compatible with the cocoon
041: * <code>Source</code> interface.
042: * Much of the code was taken from {@link AvalonToCocoonSource}.
043: *
044: * @author Stefan Köhler
045: * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
046: * @version CVS $Id: AvalonToCocoonSourceInvocationHandler.java 433543 2006-08-22 06:22:54Z crossley $
047: */
048: public class AvalonToCocoonSourceInvocationHandler implements
049: InvocationHandler {
050:
051: /** The real source */
052: protected Source source;
053:
054: /** The source resolver */
055: protected SourceResolver resolver;
056:
057: /** The environment */
058: protected Environment environment;
059:
060: /** The manager */
061: protected ComponentManager manager;
062:
063: /**
064: * Constructor
065: */
066: public AvalonToCocoonSourceInvocationHandler(Source source,
067: SourceResolver resolver, Environment environment,
068: ComponentManager manager) {
069: this .source = source;
070: this .resolver = resolver;
071: this .environment = environment;
072: this .manager = manager;
073: }
074:
075: /**
076: * Processes a method invocation on a proxy instance and returns the result.
077: * It invokes the corresponding method of the wrapped excalibur source.
078: *
079: * @param proxy the Cocoon source proxy instance that the method was invoked on
080: * @param method the Method instance corresponding to the interface method
081: * invoked on the proxy instance.
082: * @param args the arguments for the interface method
083: * @return the result of the proxy method
084: */
085: public Object invoke(Object proxy, Method method, Object[] args)
086: throws Throwable {
087: try {
088: if (method.getName().equals("getInputStream")) {
089: return this .getInputStream();
090: } else if (method.getName().equals("getInputSource")) {
091: return this .getInputSource();
092: } else if (method.getName().equals("getSystemId")) {
093: return this .getSystemId();
094: } else if (method.getName().equals("recycle")) {
095: this .recycle();
096: return null;
097: } else if (method.getName().equals("toSAX")) {
098: this .toSAX((ContentHandler) args[0]);
099: return null;
100: } else {
101: return method.invoke(source, args);
102: }
103: } catch (InvocationTargetException e) {
104: throw e.getTargetException();
105: }
106: }
107:
108: /**
109: * Return an <code>InputStream</code> object to read from the source.
110: */
111: public InputStream getInputStream() throws ProcessingException,
112: IOException {
113: try {
114: return this .source.getInputStream();
115: } catch (SourceException e) {
116: throw SourceUtil.handle(e);
117: }
118: }
119:
120: /**
121: * Return an <code>InputSource</code> object to read the XML
122: * content.
123: *
124: * @return an <code>InputSource</code> value
125: * @exception ProcessingException if an error occurs
126: * @exception IOException if an error occurs
127: */
128: public InputSource getInputSource() throws ProcessingException,
129: IOException {
130: try {
131: InputSource newObject = new InputSource(this .source
132: .getInputStream());
133: newObject.setSystemId(this .getSystemId());
134: return newObject;
135: } catch (SourceException se) {
136: throw SourceUtil.handle(se);
137: }
138: }
139:
140: /**
141: * Return the unique identifer for this source
142: */
143: public String getSystemId() {
144: return this .source.getURI();
145: }
146:
147: public void recycle() {
148: this .resolver.release(this .source);
149: this .source = null;
150: this .environment = null;
151: }
152:
153: public void refresh() {
154: this .source.refresh();
155: }
156:
157: /**
158: * Stream content to a content handler or to an XMLConsumer.
159: *
160: * @throws SAXException if failed to parse source document.
161: */
162: public void toSAX(ContentHandler handler) throws SAXException {
163: try {
164: SourceUtil.parse(this .manager, this .source, handler);
165: } catch (ProcessingException pe) {
166: throw new SAXException(
167: "ProcessingException during streaming.", pe);
168: } catch (IOException ioe) {
169: throw new SAXException("IOException during streaming.", ioe);
170: }
171: }
172:
173: /**
174: * Creates a dynamic proxy for an excalibur <code>Source</code> object to
175: * make it behave like a cocoon <code>Source</code>.
176: * @param source the source object to be wrapped
177: * @return a proxy object which implements the cocoon <code>Source</code>
178: * interface and all of the interfaces that the wrapped object
179: * implements
180: * @throws SourceException in case of an error
181: */
182: public static org.apache.cocoon.environment.Source createProxy(
183: Source source, SourceResolver resolver,
184: Environment environment, ComponentManager manager)
185: throws SourceException {
186: Class[] sourceInterfaces = source.getClass().getInterfaces();
187: Class[] proxyInterfaces = new Class[sourceInterfaces.length + 2];
188:
189: for (int i = 0; i < sourceInterfaces.length; i++) {
190: proxyInterfaces[i] = sourceInterfaces[i];
191: }
192:
193: proxyInterfaces[sourceInterfaces.length] = org.apache.cocoon.environment.Source.class;
194: proxyInterfaces[sourceInterfaces.length + 1] = ModifiableSource.class;
195:
196: InvocationHandler invocationHandler = new AvalonToCocoonSourceInvocationHandler(
197: source, resolver, environment, manager);
198:
199: try {
200: org.apache.cocoon.environment.Source proxy;
201: proxy = (org.apache.cocoon.environment.Source) Proxy
202: .newProxyInstance(source.getClass()
203: .getClassLoader(), proxyInterfaces,
204: invocationHandler);
205: return proxy;
206: } catch (Exception e) {
207: throw new SourceException("Error creating proxy object", e);
208: }
209:
210: }
211:
212: }
|