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.generation;
018:
019: import java.io.IOException;
020: import java.util.Map;
021:
022: import org.apache.avalon.framework.parameters.Parameters;
023: import org.apache.cocoon.ProcessingException;
024: import org.apache.cocoon.xml.XMLUtils;
025: import org.apache.cocoon.components.source.InspectableSource;
026: import org.apache.cocoon.components.source.LockableSource;
027: import org.apache.cocoon.components.source.RestrictableSource;
028: import org.apache.cocoon.components.source.VersionableSource;
029: import org.apache.cocoon.components.source.helpers.GroupSourcePermission;
030: import org.apache.cocoon.components.source.helpers.PrincipalSourcePermission;
031: import org.apache.cocoon.components.source.helpers.SourceLock;
032: import org.apache.cocoon.components.source.helpers.SourcePermission;
033: import org.apache.cocoon.components.source.helpers.SourceProperty;
034: import org.apache.cocoon.environment.SourceResolver;
035: import org.apache.excalibur.source.SourceException;
036: import org.apache.excalibur.source.TraversableSource;
037: import org.xml.sax.SAXException;
038: import org.xml.sax.helpers.AttributesImpl;
039:
040: /**
041: * This Generator augments the output of the TraversableGenerator.
042: * <p>
043: * It adds:
044: * <ul>
045: * <li>version information if the Source implements VersionableSource.</li>
046: * <li>locking information if the Source implements Lockablesource.</li>
047: * <li>permission information if the Source implements RestrictableSource.</li>
048: * <li>and describes its SourceProperties if the Source implements InspectableSource.</li>
049: * </ul>
050: * </p>
051: * <p>
052: * Sitemap parameters that can be specified to control processing are:
053: * <ul>
054: * <li><code>version</code> (<code>true</code>)
055: * whether to generate versioning information.</li>
056: * <li><code>locking</code> (<code>true</code>)
057: * whether to generate locking information.</li>
058: * <li><code>permission</code> (<code>true</code>)
059: * whether to generate permission information.</li>
060: * <li><code>properties</code> (<code>true</code>)
061: * whether to generate source property information.</li>
062: * </ul>
063: * </p>
064: *
065: * @author <a href="mailto:stephan@apache.org">Stephan Michels</a>
066: * @author <a href="mailto:unico@hippo.nl">Unico Hommes</a>
067: * @version $Id: TraversableSourceDescriptionGenerator.java 433543 2006-08-22 06:22:54Z crossley $
068: */
069: public class TraversableSourceDescriptionGenerator extends
070: TraversableGenerator {
071:
072: protected static final String MIME_TYPE_ATTR_NAME = "mimeType";
073:
074: private static final String REVISION_ATTR_NAME = "revision";
075: private static final String REVISIONBRANCH_ATTR_NAME = "branch";
076:
077: private static final String PROPERTIES_NODE_NAME = "properties";
078: private static final String PROPERTIES_NODE_QNAME = PREFIX + ":"
079: + PROPERTIES_NODE_NAME;
080:
081: private static final String PERMISSIONS_NODE_NAME = "permissions";
082: private static final String PERMISSIONS_NODE_QNAME = PREFIX + ":"
083: + PERMISSIONS_NODE_NAME;
084: private static final String PERMISSION_NODE_NAME = "permission";
085: private static final String PERMISSION_NODE_QNAME = PREFIX + ":"
086: + PERMISSION_NODE_NAME;
087:
088: private static final String LOCKS_NODE_NAME = "locks";
089: private static final String LOCKS_NODE_QNAME = PREFIX + ":"
090: + LOCKS_NODE_NAME;
091: private static final String LOCK_NODE_NAME = "lock";
092: private static final String LOCK_NODE_QNAME = PREFIX + ":"
093: + LOCK_NODE_NAME;
094:
095: private static final String PRINCIPAL_ATTR_NAME = "principal";
096: private static final String GROUP_ATTR_NAME = "group";
097: private static final String PRIVILEGE_ATTR_NAME = "privilege";
098: private static final String INHERITABLE_ATTR_NAME = "inheritable";
099: private static final String NEGATIVE_ATTR_NAME = "negative";
100:
101: private static final String TYPE_ATTR_NAME = "type";
102: private static final String EXPIRATION_ATTR_NAME = "expiration";
103: private static final String EXCLUSIVE_ATTR_NAME = "exclusive";
104:
105: /** Include properties into the description */
106: private boolean properties = true;
107:
108: /** Include permissions into the description */
109: private boolean permissions = true;
110:
111: /** Include locks into the description */
112: private boolean locks = true;
113:
114: /** Include version into the description */
115: private boolean version = true;
116:
117: /**
118: * Set the <code>SourceResolver</code>, objectModel <code>Map</code>,
119: * the source and sitemap <code>Parameters</code> used to process the request.
120: *
121: * @param resolver Source Resolver
122: * @param objectModel Object model.
123: * @param location Location of the source.
124: * @param parameters Parameters for the generator.
125: */
126: public void setup(SourceResolver resolver, Map objectModel,
127: String location, Parameters parameters)
128: throws ProcessingException, SAXException, IOException {
129:
130: super .setup(resolver, objectModel, location, parameters);
131:
132: this .properties = parameters.getParameterAsBoolean(
133: "properties", true);
134: super .cacheKeyParList.add(String.valueOf(String
135: .valueOf(this .properties)));
136:
137: this .permissions = parameters.getParameterAsBoolean(
138: "permissions", true);
139: super .cacheKeyParList.add(String.valueOf(this .permissions));
140:
141: this .locks = parameters.getParameterAsBoolean("locks", true);
142: super .cacheKeyParList.add(String.valueOf(this .locks));
143:
144: this .version = parameters
145: .getParameterAsBoolean("version", true);
146: super .cacheKeyParList.add(String.valueOf(this .version));
147:
148: if (getLogger().isDebugEnabled()) {
149: getLogger().debug("properties: " + this .properties);
150: getLogger().debug("permissions: " + this .permissions);
151: getLogger().debug("locks: " + this .locks);
152: getLogger().debug("version: " + this .version);
153: }
154: }
155:
156: /**
157: * Augments source nodes with additional information.
158: *
159: * @param source the Source to describe.
160: */
161: protected final void addContent(TraversableSource source)
162: throws SAXException, ProcessingException {
163:
164: super .addContent(source);
165: try {
166: if (this .properties
167: && (source instanceof InspectableSource)) {
168: pushSourceProperties((InspectableSource) source);
169: }
170: if (this .permissions
171: && (source instanceof RestrictableSource)) {
172: pushSourcePermissions((RestrictableSource) source);
173: }
174: if (this .locks && (source instanceof LockableSource)) {
175: pushSourceLocks((LockableSource) source);
176: }
177: } catch (SourceException e) {
178: throw new ProcessingException(e);
179: }
180:
181: }
182:
183: /**
184: * Augments source node elements with additional attributes describing the Source.
185: * The additional attributes are a <code>mimeType</code> attribute,
186: * and iff the Source is an instance of VersionableSource and the generator
187: * is configured to output versioning information two attributes:
188: * <code>revision</code> and <code>branch</code>.
189: *
190: * @param source the Source to describe.
191: */
192: protected void setNodeAttributes(TraversableSource source)
193: throws SAXException, ProcessingException {
194: super .setNodeAttributes(source);
195: if (!source.isCollection()) {
196: String mimeType = source.getMimeType();
197: if (mimeType != null) {
198: attributes.addAttribute("", MIME_TYPE_ATTR_NAME,
199: MIME_TYPE_ATTR_NAME, "CDATA", source
200: .getMimeType());
201: }
202: }
203: if (this .version && source instanceof VersionableSource) {
204: try {
205: VersionableSource versionablesource = (VersionableSource) source;
206: if (versionablesource.isVersioned()) {
207: if ((versionablesource.getSourceRevision() != null)
208: && (versionablesource.getSourceRevision()
209: .length() > 0)) {
210: attributes.addAttribute("", REVISION_ATTR_NAME,
211: REVISION_ATTR_NAME, "CDATA",
212: versionablesource.getSourceRevision());
213: }
214:
215: if ((versionablesource.getSourceRevisionBranch() != null)
216: && (versionablesource
217: .getSourceRevisionBranch().length() > 0)) {
218: attributes.addAttribute("",
219: REVISIONBRANCH_ATTR_NAME,
220: REVISIONBRANCH_ATTR_NAME, "CDATA",
221: versionablesource
222: .getSourceRevisionBranch());
223: }
224: }
225: } catch (SourceException e) {
226: throw new ProcessingException(e);
227: }
228: }
229: }
230:
231: /**
232: * Push a XML description about all properties, which
233: * the source owns.
234: *
235: * @param source the Source to describe.
236: */
237: private void pushSourceProperties(InspectableSource source)
238: throws SAXException, SourceException {
239:
240: SourceProperty[] properties = source.getSourceProperties();
241: if (properties != null && properties.length > 0) {
242: this .contentHandler.startElement(URI, PROPERTIES_NODE_NAME,
243: PROPERTIES_NODE_QNAME, XMLUtils.EMPTY_ATTRIBUTES);
244: for (int i = 0; i < properties.length; i++) {
245: SourceProperty property = properties[i];
246: property.toSAX(this .contentHandler);
247: }
248: this .contentHandler.endElement(URI, PROPERTIES_NODE_NAME,
249: PROPERTIES_NODE_QNAME);
250: }
251: }
252:
253: /**
254: * Push a XML description of all permissions of a source.
255: *
256: * @param source the Source to describe.
257: */
258: private void pushSourcePermissions(RestrictableSource source)
259: throws SAXException, SourceException {
260: SourcePermission[] permissions = source.getSourcePermissions();
261:
262: if (permissions != null && permissions.length > 0) {
263: this .contentHandler.startElement(URI,
264: PERMISSIONS_NODE_NAME, PERMISSIONS_NODE_QNAME,
265: XMLUtils.EMPTY_ATTRIBUTES);
266:
267: for (int i = 0; i < permissions.length; i++) {
268: AttributesImpl attributes = new AttributesImpl();
269:
270: if (permissions[i] instanceof PrincipalSourcePermission) {
271: attributes
272: .addAttribute(
273: "",
274: PRINCIPAL_ATTR_NAME,
275: PRINCIPAL_ATTR_NAME,
276: "CDATA",
277: ((PrincipalSourcePermission) permissions[i])
278: .getPrincipal());
279: } else if (permissions[i] instanceof GroupSourcePermission) {
280: attributes.addAttribute("", GROUP_ATTR_NAME,
281: GROUP_ATTR_NAME, "CDATA",
282: ((GroupSourcePermission) permissions[i])
283: .getGroup());
284: }
285:
286: attributes.addAttribute("", PRIVILEGE_ATTR_NAME,
287: PRIVILEGE_ATTR_NAME, "CDATA", permissions[i]
288: .getPrivilege());
289: attributes.addAttribute("", INHERITABLE_ATTR_NAME,
290: INHERITABLE_ATTR_NAME, "CDATA",
291: String.valueOf(permissions[i].isInheritable()));
292: attributes.addAttribute("", NEGATIVE_ATTR_NAME,
293: NEGATIVE_ATTR_NAME, "CDATA", String
294: .valueOf(permissions[i].isNegative()));
295:
296: this .contentHandler.startElement(URI,
297: PERMISSION_NODE_NAME, PERMISSION_NODE_QNAME,
298: attributes);
299: this .contentHandler.endElement(URI,
300: PERMISSION_NODE_NAME, PERMISSION_NODE_QNAME);
301: }
302:
303: this .contentHandler.endElement(URI, PERMISSIONS_NODE_NAME,
304: PERMISSIONS_NODE_QNAME);
305: }
306: }
307:
308: /**
309: * Push a XML description about all locks of a source.
310: *
311: * @param source the Source to describe.
312: */
313: public void pushSourceLocks(LockableSource source)
314: throws SAXException, SourceException {
315: SourceLock[] locks = source.getSourceLocks();
316:
317: if (locks != null && locks.length > 0) {
318: this .contentHandler.startElement(URI, LOCKS_NODE_NAME,
319: LOCKS_NODE_QNAME, XMLUtils.EMPTY_ATTRIBUTES);
320:
321: for (int i = 0; locks.length > 0; i++) {
322: SourceLock lock = locks[i];
323:
324: AttributesImpl attributes = new AttributesImpl();
325: attributes
326: .addAttribute("", PRINCIPAL_ATTR_NAME,
327: PRINCIPAL_ATTR_NAME, "CDATA", lock
328: .getSubject());
329: attributes.addAttribute("", TYPE_ATTR_NAME,
330: TYPE_ATTR_NAME, "CDATA", lock.getType());
331: attributes.addAttribute("", EXPIRATION_ATTR_NAME,
332: EXPIRATION_ATTR_NAME, "CDATA", lock
333: .getExpiration().toString());
334: attributes.addAttribute("", INHERITABLE_ATTR_NAME,
335: INHERITABLE_ATTR_NAME, "CDATA", String
336: .valueOf(lock.isInheritable()));
337: attributes.addAttribute("", EXCLUSIVE_ATTR_NAME,
338: EXCLUSIVE_ATTR_NAME, "CDATA", String
339: .valueOf(lock.isExclusive()));
340:
341: this.contentHandler.startElement(URI, LOCK_NODE_NAME,
342: LOCK_NODE_QNAME, attributes);
343: this.contentHandler.endElement(URI, LOCK_NODE_NAME,
344: LOCK_NODE_QNAME);
345: }
346:
347: this.contentHandler.endElement(URI, LOCKS_NODE_NAME,
348: LOCKS_NODE_QNAME);
349: }
350: }
351:
352: }
|