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 java.io.InputStream;
020: import java.io.IOException;
021: import java.io.ByteArrayInputStream;
022: import java.net.MalformedURLException;
023: import java.util.Map;
024:
025: import org.apache.avalon.framework.configuration.ConfigurationException;
026: import org.apache.avalon.framework.logger.Logger;
027: import org.apache.avalon.framework.service.ServiceException;
028: import org.apache.avalon.framework.service.ServiceManager;
029: import org.apache.avalon.framework.service.ServiceSelector;
030:
031: import org.apache.excalibur.source.SourceException;
032: import org.apache.excalibur.source.impl.AbstractSource;
033:
034: import org.apache.cocoon.components.modules.input.InputModule;
035:
036: import org.apache.commons.jxpath.JXPathContext;
037:
038: /**
039: * A <code>Source</code> that takes its content from a
040: * module.
041: * <p>The URI syntax is
042: * "module:<input-module>:<attribute-name>[#XPath]",
043: * where :
044: * <ul>
045: * <li>an input-module name is used for finding an input-module for reading data from</li>,
046: * <li>"attribute-name" is the name of the attribute found in the module</li>,
047: * <li>"XPath" is an XPath that is aplied on the object in the
048: * attribute, by using JXPath.</li>
049: * </ul>
050: * </p>
051: *
052: * @author <a href="mailto:danielf@nada.kth.se">Daniel Fagerstom</a>
053: */
054:
055: public class ModuleSource extends AbstractSource {
056:
057: private final static String SCHEME = "module";
058: private String attributeType;
059: private String attributeName;
060: private String xPath;
061: private ServiceManager manager;
062: private Map objectModel;
063: private Logger logger;
064:
065: /**
066: * Create a module source from a 'module:' uri and a the object model.
067: * <p>The uri is of the form "module:attribute-type:attribute-name#xpath</p>
068: */
069: public ModuleSource(Map objectModel, String uri,
070: ServiceManager manager, Logger logger)
071: throws MalformedURLException {
072:
073: this .objectModel = objectModel;
074: this .manager = manager;
075: this .logger = logger;
076:
077: setSystemId(uri);
078:
079: // Scheme
080: int start = 0;
081: int end = uri.indexOf(':');
082: if (end == -1)
083: throw new MalformedURLException(
084: "Malformed uri for module source (cannot find scheme) : "
085: + uri);
086:
087: String scheme = uri.substring(start, end);
088: if (!SCHEME.equals(scheme))
089: throw new MalformedURLException(
090: "Malformed uri for a module source : " + uri);
091:
092: setScheme(scheme);
093:
094: // Attribute type
095: start = end + 1;
096: end = uri.indexOf(':', start);
097: if (end == -1) {
098: throw new MalformedURLException(
099: "Malformed uri for module source (cannot find attribute type) : "
100: + uri);
101: }
102: this .attributeType = uri.substring(start, end);
103:
104: // Attribute name
105: start = end + 1;
106: end = uri.indexOf('#', start);
107:
108: if (end == -1)
109: end = uri.length();
110:
111: if (end == start)
112: throw new MalformedURLException(
113: "Malformed uri for module source (cannot find attribute name) : "
114: + uri);
115:
116: this .attributeName = uri.substring(start, end);
117:
118: // xpath
119: start = end + 1;
120: this .xPath = start < uri.length() ? uri.substring(start) : "";
121: }
122:
123: /**
124: * Return an <code>InputStream</code> object to read from the source.
125: *
126: * @throws IOException if I/O error occured.
127: */
128: public InputStream getInputStream() throws IOException,
129: SourceException {
130: if (this .logger.isDebugEnabled()) {
131: this .logger.debug("Getting InputStream for " + getURI());
132: }
133:
134: Object obj = getInputAttribute(this .attributeType,
135: this .attributeName);
136: if (obj == null)
137: throw new SourceException(" The attribute: "
138: + this .attributeName + " is empty");
139:
140: if (!(this .xPath.length() == 0 || this .xPath.equals("/"))) {
141: JXPathContext context = JXPathContext.newContext(obj);
142: obj = context.getValue(this .xPath);
143:
144: if (obj == null)
145: throw new SourceException("the xpath: " + this .xPath
146: + " applied on the attribute: "
147: + this .attributeName + " returns null");
148: }
149:
150: if (obj instanceof InputStream) {
151: return (InputStream) obj;
152: } else if (obj instanceof String) {
153: return new ByteArrayInputStream(((String) obj).getBytes());
154: } else if (obj instanceof byte[]) {
155: return new ByteArrayInputStream((byte[]) obj);
156: } else {
157: throw new SourceException("The object type: "
158: + obj.getClass()
159: + " could not be serialized as a InputStream "
160: + obj);
161: }
162: }
163:
164: /**
165: * Does this source actually exist ?
166: *
167: * @return true if the resource exists.
168: *
169: */
170: public boolean exists() {
171: boolean exists = false;
172: try {
173: exists = getInputAttribute(this .attributeType,
174: this .attributeName) != null;
175: } catch (SourceException e) {
176: exists = false;
177: }
178: return exists;
179: }
180:
181: private Object getInputAttribute(String inputModuleName,
182: String attributeName) throws SourceException {
183: Object obj;
184: ServiceSelector selector = null;
185: InputModule inputModule = null;
186: try {
187: selector = (ServiceSelector) this .manager
188: .lookup(InputModule.ROLE + "Selector");
189: inputModule = (InputModule) selector
190: .select(inputModuleName);
191: obj = inputModule.getAttribute(attributeName, null,
192: this .objectModel);
193:
194: } catch (ServiceException e) {
195: throw new SourceException(
196: "Could not find an InputModule of the type "
197: + inputModuleName, e);
198: } catch (ConfigurationException e) {
199: throw new SourceException("Could not find an attribute: "
200: + attributeName + " from the InputModule "
201: + inputModuleName, e);
202: } finally {
203: if (inputModule != null)
204: selector.release(inputModule);
205: this.manager.release(selector);
206: }
207:
208: return obj;
209: }
210: }
|