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: */
018: package org.apache.lenya.cms.repository;
019:
020: import java.util.ArrayList;
021: import java.util.HashMap;
022: import java.util.List;
023: import java.util.Map;
024:
025: import org.apache.avalon.framework.service.ServiceException;
026: import org.apache.avalon.framework.service.ServiceManager;
027: import org.apache.lenya.cms.cocoon.source.SourceUtil;
028: import org.apache.lenya.cms.metadata.ElementSet;
029: import org.apache.lenya.cms.metadata.MetaData;
030: import org.apache.lenya.cms.metadata.MetaDataException;
031: import org.apache.lenya.cms.metadata.MetaDataOwner;
032: import org.apache.lenya.cms.metadata.MetaDataRegistry;
033: import org.apache.lenya.cms.metadata.dublincore.DublinCore;
034: import org.apache.lenya.cms.publication.PageEnvelope;
035: import org.apache.lenya.xml.DocumentHelper;
036: import org.apache.lenya.xml.NamespaceHelper;
037: import org.w3c.dom.Document;
038: import org.w3c.dom.Element;
039:
040: /**
041: * Handles the meta data of source nodes.
042: */
043: public class SourceNodeMetaDataHandler implements MetaDataOwner {
044:
045: private ServiceManager manager;
046: private String sourceUri;
047:
048: /**
049: * @param manager The service manager.
050: * @param sourceUri The soure URI.
051: */
052: public SourceNodeMetaDataHandler(ServiceManager manager,
053: String sourceUri) {
054: this .manager = manager;
055: this .sourceUri = sourceUri;
056: }
057:
058: private Map namespace2metadata = new HashMap();
059:
060: public MetaData getMetaData(String namespaceUri)
061: throws MetaDataException {
062:
063: MetaData meta = (MetaData) this .namespace2metadata
064: .get(namespaceUri);
065: if (meta == null) {
066:
067: MetaDataRegistry registry = null;
068: try {
069: registry = (MetaDataRegistry) this .manager
070: .lookup(MetaDataRegistry.ROLE);
071: if (!registry.isRegistered(namespaceUri)) {
072: throw new MetaDataException("The namespace ["
073: + namespaceUri + "] is not registered!");
074: }
075: } catch (ServiceException e) {
076: throw new MetaDataException(e);
077: } finally {
078: if (registry != null) {
079: this .manager.release(registry);
080: }
081: }
082:
083: synchronized (this ) {
084: meta = new SourceNodeMetaData(namespaceUri, this ,
085: this .manager);
086: this .namespace2metadata.put(namespaceUri, meta);
087: }
088: }
089: return meta;
090: }
091:
092: protected Map namespace2metamap = null;
093:
094: protected synchronized Map getMetaDataMap(String namespaceUri)
095: throws MetaDataException {
096: if (this .namespace2metamap == null) {
097: loadMetaData();
098: }
099: Map map = (Map) this .namespace2metamap.get(namespaceUri);
100: if (map == null) {
101: map = new HashMap();
102: this .namespace2metamap.put(namespaceUri, map);
103: }
104: return map;
105: }
106:
107: protected static final String META_DATA_NAMESPACE = "http://apache.org/lenya/metadata/1.0";
108: protected static final String ELEMENT_METADATA = "metadata";
109: protected static final String ELEMENT_SET = "element-set";
110: protected static final String ELEMENT_ELEMENT = "element";
111: protected static final String ELEMENT_VALUE = "value";
112: protected static final String ATTRIBUTE_NAMESPACE = "namespace";
113: protected static final String ATTRIBUTE_KEY = "key";
114:
115: protected synchronized void loadMetaData() throws MetaDataException {
116:
117: if (this .namespace2metamap != null) {
118: throw new IllegalStateException(
119: "The meta data have already been loaded!");
120: }
121:
122: try {
123: this .namespace2metamap = new HashMap();
124: if (SourceUtil.exists(this .sourceUri, this .manager)) {
125: Document xml = SourceUtil.readDOM(this .sourceUri,
126: this .manager);
127: if (!xml.getDocumentElement().getNamespaceURI().equals(
128: META_DATA_NAMESPACE)) {
129: loadLegacyMetaData(xml);
130: } else {
131: NamespaceHelper helper = new NamespaceHelper(
132: META_DATA_NAMESPACE, "", xml);
133: Element[] setElements = helper.getChildren(xml
134: .getDocumentElement(), ELEMENT_SET);
135: for (int setIndex = 0; setIndex < setElements.length; setIndex++) {
136: String namespace = setElements[setIndex]
137: .getAttribute(ATTRIBUTE_NAMESPACE);
138: Element[] elementElements = helper.getChildren(
139: setElements[setIndex], ELEMENT_ELEMENT);
140: Map element2values = new HashMap();
141: for (int elemIndex = 0; elemIndex < elementElements.length; elemIndex++) {
142: String key = elementElements[elemIndex]
143: .getAttribute(ATTRIBUTE_KEY);
144: Element[] valueElements = helper
145: .getChildren(
146: elementElements[elemIndex],
147: ELEMENT_VALUE);
148: List values = new ArrayList();
149: for (int valueIndex = 0; valueIndex < valueElements.length; valueIndex++) {
150: String value = DocumentHelper
151: .getSimpleElementText(valueElements[valueIndex]);
152: values.add(value);
153: }
154: element2values.put(key, values);
155: }
156: this .namespace2metamap.put(namespace,
157: element2values);
158: }
159: }
160: }
161: } catch (Exception e) {
162: throw new MetaDataException(e);
163: }
164: }
165:
166: protected void loadLegacyMetaData(Document xml)
167: throws MetaDataException {
168: NamespaceHelper helper = new NamespaceHelper(
169: PageEnvelope.NAMESPACE, "", xml);
170:
171: Element metaElement = helper.getFirstChild(xml
172: .getDocumentElement(), "meta");
173:
174: Element internalElement = helper.getFirstChild(metaElement,
175: "internal");
176:
177: Element[] internalElements = helper
178: .getChildren(internalElement);
179: for (int i = 0; i < internalElements.length; i++) {
180: String value = DocumentHelper
181: .getSimpleElementText(internalElements[i]);
182: String key = internalElements[i].getLocalName();
183:
184: if (key.equals("workflowVersion")) {
185: List values = getValueList(
186: "http://apache.org/lenya/metadata/workflow/1.0",
187: key);
188: values.add(value);
189: } else {
190: List values = getValueList(
191: "http://apache.org/lenya/metadata/document/1.0",
192: key);
193: values.add(value);
194: }
195: }
196:
197: NamespaceHelper dcHelper = new NamespaceHelper(
198: DublinCore.DC_NAMESPACE, "", xml);
199: Element dcElement = helper.getFirstChild(metaElement, "dc");
200:
201: if (dcElement != null) {
202: MetaDataRegistry registry = null;
203: try {
204: registry = (MetaDataRegistry) this .manager
205: .lookup(MetaDataRegistry.ROLE);
206: ElementSet dcElementSet = registry
207: .getElementSet(DublinCore.DC_NAMESPACE);
208: ElementSet dcTermSet = registry
209: .getElementSet(DublinCore.DCTERMS_NAMESPACE);
210:
211: Element[] dcElements = dcHelper.getChildren(dcElement);
212: for (int i = 0; i < dcElements.length; i++) {
213: String value = DocumentHelper
214: .getSimpleElementText(dcElements[i]);
215:
216: String key = dcElements[i].getLocalName();
217:
218: if (dcElementSet.containsElement(key)) {
219: List values = getValueList(
220: DublinCore.DC_NAMESPACE, key);
221: values.add(value);
222: } else if (dcTermSet.containsElement(key)) {
223: List values = getValueList(
224: DublinCore.DCTERMS_NAMESPACE, key);
225: values.add(value);
226: } else {
227: throw new RepositoryException(
228: "The dublin core key [" + key
229: + "] is not supported.");
230: }
231: }
232: } catch (MetaDataException e) {
233: throw e;
234: } catch (Exception e) {
235: throw new MetaDataException(e);
236: } finally {
237: if (registry != null) {
238: this .manager.release(registry);
239: }
240: }
241: }
242:
243: }
244:
245: protected String[] getValues(String namespaceUri, String key,
246: int revisionNumber) throws MetaDataException {
247: List values = getValueList(namespaceUri, key);
248: return (String[]) values.toArray(new String[values.size()]);
249: }
250:
251: protected String[] getValues(String namespaceUri, String key)
252: throws MetaDataException {
253: List values = getValueList(namespaceUri, key);
254: return (String[]) values.toArray(new String[values.size()]);
255: }
256:
257: protected List getValueList(String namespaceUri, String key)
258: throws MetaDataException {
259: Map map = getMetaDataMap(namespaceUri);
260: List values = (List) map.get(key);
261: if (values == null) {
262: synchronized (this ) {
263: values = new ArrayList();
264: map.put(key, values);
265: }
266: }
267: return values;
268: }
269:
270: protected void addValue(String namespaceUri, String key,
271: String value) throws MetaDataException {
272: throw new IllegalStateException("Operation not supported");
273: }
274:
275: protected void removeAllValues(String namespaceUri, String key)
276: throws MetaDataException {
277: throw new IllegalStateException("Operation not supported");
278: }
279:
280: protected void setValue(String namespaceUri, String key,
281: String value) throws MetaDataException {
282: throw new IllegalStateException("Operation not supported");
283: }
284:
285: public String[] getMetaDataNamespaceUris() throws MetaDataException {
286: MetaDataRegistry registry = null;
287: try {
288: registry = (MetaDataRegistry) this .manager
289: .lookup(MetaDataRegistry.ROLE);
290: return registry.getNamespaceUris();
291: } catch (ServiceException e) {
292: throw new MetaDataException(e);
293: } finally {
294: if (registry != null) {
295: this .manager.release(registry);
296: }
297: }
298: }
299:
300: protected long getLastModified() throws RepositoryException {
301: try {
302: return SourceUtil.getLastModified(this .sourceUri,
303: this .manager);
304: } catch (Exception e) {
305: throw new RepositoryException(e);
306: }
307: }
308:
309: }
|