- add moved class to core-metadata
git-svn-id: https://svn.apache.org/repos/asf/lenya/trunk@1034324 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/CacheableMetaData.java b/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/CacheableMetaData.java
new file mode 100644
index 0000000..0222a05
--- /dev/null
+++ b/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/CacheableMetaData.java
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.lenya.cms.metadata;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Cached, read-only meta data.
+ */
+public class CacheableMetaData implements MetaData {
+
+ /**
+ * Maps keys to value arrays.
+ */
+ private Map key2values = new HashMap();
+ private long lastModified;
+ private ElementSet elementSet;
+
+ /**
+ * @param meta The meta data to build this object from.
+ */
+ public CacheableMetaData(MetaData meta) {
+ this.elementSet = meta.getElementSet();
+ String[] keys = meta.getAvailableKeys();
+ try {
+ this.lastModified = meta.getLastModified();
+ for (int i = 0; i < keys.length; i++) {
+ String[] values = meta.getValues(keys[i]);
+ this.key2values.put(keys[i], values);
+ }
+ } catch (MetaDataException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void addValue(String key, String value) throws MetaDataException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void forcedReplaceBy(MetaData other) throws MetaDataException {
+ throw new UnsupportedOperationException();
+ }
+
+ public String[] getAvailableKeys() {
+ Set keys = key2values.keySet();
+ return (String[]) keys.toArray(new String[keys.size()]);
+ }
+
+ public ElementSet getElementSet() {
+ return this.elementSet;
+ }
+
+ public String getFirstValue(String key) throws MetaDataException {
+ String value = null;
+ String[] values = getValues(key);
+ if (values.length > 0) {
+ value = values[0];
+ }
+ return value;
+ }
+
+ public long getLastModified() throws MetaDataException {
+ return this.lastModified;
+ }
+
+ private String[] possibleKeys;
+
+ public String[] getPossibleKeys() {
+ if (this.possibleKeys == null) {
+ Element[] elements = getElementSet().getElements();
+ this.possibleKeys = new String[elements.length];
+ for (int i = 0; i < possibleKeys.length; i++) {
+ possibleKeys[i] = elements[i].getName();
+ }
+ }
+ return this.possibleKeys;
+ }
+
+ public String[] getValues(String key) throws MetaDataException {
+ if (this.key2values.containsKey(key)) {
+ return (String[]) this.key2values.get(key);
+ }
+ else {
+ return new String[0];
+ }
+ }
+
+ public boolean isValidAttribute(String key) {
+ return Arrays.asList(getPossibleKeys()).contains(key);
+ }
+
+ public void removeAllValues(String key) throws MetaDataException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void replaceBy(MetaData other) throws MetaDataException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setValue(String key, String value) throws MetaDataException {
+ throw new UnsupportedOperationException();
+ }
+
+}
diff --git a/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/Element.java b/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/Element.java
new file mode 100644
index 0000000..2eb5c03
--- /dev/null
+++ b/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/Element.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.lenya.cms.metadata;
+
+/**
+ * A meta data element.
+ */
+public interface Element {
+
+ /**
+ * @return the name of the element.
+ */
+ String getName();
+
+ /**
+ * @return if the element can have multiple values.
+ */
+ boolean isMultiple();
+
+ /**
+ * @return the description of the element.
+ */
+ String getDescription();
+
+ /**
+ * @return if the element value can be edited.
+ */
+ boolean isEditable();
+
+ /**
+ * Copy all values if the meta data are copied.
+ */
+ int ONCOPY_COPY = 0;
+
+ /**
+ * Don't copy the values of this element if the meta data are copied.
+ */
+ int ONCOPY_IGNORE = 1;
+
+ /**
+ * Delete all values of this element if the meta data are copied.
+ */
+ int ONCOPY_DELETE = 2;
+
+ /**
+ * @return The action to be taken when meta data are copied from one owner to another.
+ */
+ int getActionOnCopy();
+
+ /**
+ * @return If this element shall be included in search queries.
+ */
+ boolean isSearchable();
+
+}
diff --git a/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/ElementSet.java b/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/ElementSet.java
new file mode 100644
index 0000000..bbc1a61
--- /dev/null
+++ b/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/ElementSet.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.lenya.cms.metadata;
+
+/**
+ * Definition of a set of meta data elements.
+ */
+public interface ElementSet {
+
+ /**
+ * @return The supported elements.
+ */
+ Element[] getElements();
+
+ /**
+ * @param name The name.
+ * @return The element.
+ * @throws MetaDataException if the element with this name does not exist.
+ */
+ Element getElement(String name) throws MetaDataException;
+
+ /**
+ * @return The namespace URI of this element set.
+ */
+ String getNamespaceUri();
+
+ /**
+ * Checks if an element with a certain name is contained.
+ * @param name The name.
+ * @return A boolean value.
+ */
+ boolean containsElement(String name);
+
+}
diff --git a/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/ElementSetWrapper.java b/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/ElementSetWrapper.java
new file mode 100644
index 0000000..3a57a6d
--- /dev/null
+++ b/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/ElementSetWrapper.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.lenya.cms.metadata;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.lenya.cms.repository.metadata.ElementSet;
+import org.apache.lenya.cms.repository.metadata.MetaDataException;
+
+public class ElementSetWrapper implements org.apache.lenya.cms.metadata.ElementSet {
+
+ private org.apache.lenya.cms.repository.metadata.ElementSet delegate;
+ private Map<String, ElementWrapper> elements = new HashMap<String, ElementWrapper>();
+
+ public ElementSetWrapper(ElementSet delegate) {
+ super();
+ this.delegate = delegate;
+ }
+
+ public boolean containsElement(String name) {
+ return this.delegate.containsElement(name);
+ }
+
+ public Element getElement(String name) throws org.apache.lenya.cms.metadata.MetaDataException {
+ ElementWrapper wrapper = this.elements.get(name);
+ if (wrapper == null) {
+ try {
+ wrapper = new ElementWrapper(this.delegate.getElement(name));
+ } catch (MetaDataException e) {
+ throw new org.apache.lenya.cms.metadata.MetaDataException(e);
+ }
+ this.elements.put(name, wrapper);
+ }
+ return wrapper;
+ }
+
+ public Element[] getElements() {
+ org.apache.lenya.cms.repository.metadata.Element[] elements = this.delegate.getElements();
+ Element[] wrappers = new Element[elements.length];
+ for (int i = 0; i < elements.length; i++) {
+ try {
+ wrappers[i] = getElement(elements[i].getName());
+ } catch (org.apache.lenya.cms.metadata.MetaDataException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return wrappers;
+ }
+
+ public String getNamespaceUri() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/ElementWrapper.java b/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/ElementWrapper.java
new file mode 100644
index 0000000..5f43b69
--- /dev/null
+++ b/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/ElementWrapper.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.lenya.cms.metadata;
+
+import org.apache.lenya.cms.repository.metadata.Element;
+
+public class ElementWrapper implements org.apache.lenya.cms.metadata.Element {
+
+ private org.apache.lenya.cms.repository.metadata.Element delegate;
+
+ public ElementWrapper(Element delegate) {
+ this.delegate = delegate;
+ }
+
+ public int getActionOnCopy() {
+ return this.delegate.getActionOnCopy();
+ }
+
+ public String getDescription() {
+ return this.delegate.getDescription();
+ }
+
+ public String getName() {
+ return this.delegate.getName();
+ }
+
+ public boolean isEditable() {
+ return this.delegate.isEditable();
+ }
+
+ public boolean isMultiple() {
+ return this.delegate.isMultiple();
+ }
+
+ public boolean isSearchable() {
+ return this.delegate.isSearchable();
+ }
+
+}
diff --git a/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/MetaData.java b/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/MetaData.java
new file mode 100644
index 0000000..2207aa4
--- /dev/null
+++ b/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/MetaData.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.lenya.cms.metadata;
+
+/**
+ * Generic meta data interface.
+ *
+ * @version $Id$
+ */
+public interface MetaData {
+
+ /**
+ * Returns the values for a certain key.
+ * @param key The key.
+ * @return An array of strings.
+ * @throws MetaDataException when something went wrong.
+ */
+ String[] getValues(String key) throws MetaDataException;
+
+ /**
+ * Returns the first value for a certain key.
+ * @param key The key.
+ * @return A string or <code>null</code> if no value is set for this key.
+ * @throws MetaDataException if an error occurs.
+ */
+ String getFirstValue(String key) throws MetaDataException;
+
+ /**
+ * Get all available keys.
+ * @return The keys available in this MetaData object.
+ */
+ String[] getAvailableKeys();
+
+ /**
+ * Sets the value for a certain key. All existing values will be removed.
+ * @param key The key.
+ * @param value The value to set.
+ * @throws MetaDataException when something went wrong.
+ */
+ void setValue(String key, String value) throws MetaDataException;
+
+ /**
+ * Addds a value for a certain key. The existing values will not be removed.
+ * @param key The key.
+ * @param value The value to add.
+ * @throws MetaDataException if there's already a value set and the element doesn't support multiple values.
+ */
+ void addValue(String key, String value) throws MetaDataException;
+
+ /**
+ * Replace the contents of the current meta data by the contents of other.
+ * @param other The other meta data manager.
+ * @throws MetaDataException if an error occurs.
+ */
+ void replaceBy(MetaData other) throws MetaDataException;
+
+ /**
+ * Replace the contents of the current meta data by the contents of other.
+ * All meta data is replaced, disregarding the rules given by element.getActionOnCopy().
+ * @param other The other meta data manager.
+ * @throws MetaDataException if an error occurs.
+ */
+ void forcedReplaceBy(MetaData other) throws MetaDataException;
+
+ /**
+ * @return All keys that can be used.
+ */
+ String[] getPossibleKeys();
+
+ /**
+ * Checks if a key represents a valid metadata attribute.
+ * @param key The key.
+ * @return A boolean value.
+ */
+ boolean isValidAttribute(String key);
+
+ /**
+ * Get last modification date.
+ * @return last modification date
+ * @throws MetaDataException if an error occurs.
+ */
+ long getLastModified() throws MetaDataException;
+
+ /**
+ * @return The element set this meta data object belongs to.
+ */
+ ElementSet getElementSet();
+
+ /**
+ * Removes all values for a certain key.
+ * @param key The key.
+ * @throws MetaDataException if the key is not supported.
+ */
+ void removeAllValues(String key) throws MetaDataException;
+
+}
diff --git a/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/MetaDataCache.java b/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/MetaDataCache.java
new file mode 100644
index 0000000..6aa3037
--- /dev/null
+++ b/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/MetaDataCache.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.lenya.cms.metadata;
+
+import org.apache.cocoon.spring.configurator.WebAppContextUtils;
+import org.apache.excalibur.store.impl.MRUMemoryStore;
+import org.apache.lenya.cms.metadata.CacheableMetaData;
+import org.apache.lenya.cms.metadata.MetaData;
+import org.apache.lenya.cms.metadata.MetaDataException;
+
+/**
+ * Cache for meta data.
+ */
+public class MetaDataCache {
+
+ public static final String ROLE = MetaDataCache.class.getName();
+ protected static final String STORE_ROLE = MetaDataCache.ROLE + "Store";
+ private MRUMemoryStore store;
+
+ /**
+ * Get a meta data object from the cache.
+ * @param document The document.
+ * @param namespaceUri The namespace URI.
+ * @return A meta data object.
+ * @throws MetaDataException if an error occurs.
+ */
+ public synchronized MetaData getMetaData(String cacheKey, MetaData meta, String namespaceUri)
+ throws MetaDataException {
+ MRUMemoryStore store = getStore();
+ String key = getCacheKey(cacheKey, namespaceUri);
+
+ MetaData cachedMeta = null;
+ if (store.containsKey(key)) {
+ cachedMeta = (MetaData) store.get(key);
+ if (meta.getLastModified() > cachedMeta.getLastModified()) {
+ cachedMeta = null;
+ }
+ }
+ if (cachedMeta == null) {
+ cachedMeta = new CacheableMetaData(meta);
+ store.hold(key, cachedMeta);
+ }
+ return cachedMeta;
+ }
+
+ protected String getCacheKey(String cacheKey, String namespaceUri) {
+ return cacheKey + ":" + namespaceUri;
+ }
+
+ protected MRUMemoryStore getStore() {
+ if (this.store == null) {
+ synchronized (this) {
+ this.store = (MRUMemoryStore) WebAppContextUtils.getCurrentWebApplicationContext()
+ .getBean(STORE_ROLE);
+ }
+ }
+ return this.store;
+ }
+
+}
diff --git a/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/MetaDataException.java b/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/MetaDataException.java
new file mode 100644
index 0000000..fdec9dd
--- /dev/null
+++ b/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/MetaDataException.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.lenya.cms.metadata;
+
+/**
+ * Meta data exception.
+ */
+public class MetaDataException extends Exception {
+
+ /**
+ *
+ */
+ public MetaDataException() {
+ super();
+ }
+
+ /**
+ * @param arg0
+ * @param arg1
+ */
+ public MetaDataException(String arg0, Throwable arg1) {
+ super(arg0, arg1);
+ }
+
+ /**
+ * @param arg0
+ */
+ public MetaDataException(String arg0) {
+ super(arg0);
+ }
+
+ /**
+ * @param arg0
+ */
+ public MetaDataException(Throwable arg0) {
+ super(arg0);
+ }
+
+}
diff --git a/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/MetaDataOwner.java b/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/MetaDataOwner.java
new file mode 100644
index 0000000..16ba4c5
--- /dev/null
+++ b/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/MetaDataOwner.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.lenya.cms.metadata;
+
+/**
+ * Owner of meta-data.
+ *
+ * @version $Id$
+ */
+public interface MetaDataOwner {
+
+ /**
+ * Returns a meta data object.
+ * @param namespaceUri The namespace URI.
+ * @return A meta data object.
+ * @throws MetaDataException if an error occurs.
+ */
+ MetaData getMetaData(String namespaceUri) throws MetaDataException;
+
+ /**
+ * Returns the URIs of the meta data currently supported by the owner.
+ * @return An array of strings.
+ * @throws MetaDataException if an error occurs.
+ */
+ String[] getMetaDataNamespaceUris() throws MetaDataException;
+
+}
diff --git a/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/MetaDataRegistry.java b/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/MetaDataRegistry.java
new file mode 100644
index 0000000..db06f2a
--- /dev/null
+++ b/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/MetaDataRegistry.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.lenya.cms.metadata;
+
+/**
+ * Meta data registry.
+ */
+public interface MetaDataRegistry {
+
+ /**
+ * The service role.
+ */
+ String ROLE = MetaDataRegistry.class.getName();
+
+ /**
+ * @param namespaceUri The namespace URI of the element set.
+ * @return the element set.
+ * @throws MetaDataException if an error occurs.
+ */
+ ElementSet getElementSet(String namespaceUri) throws MetaDataException;
+
+ /**
+ * Checks if an element set is registered.
+ * @param namespaceUri The namespace URI.
+ * @return A boolean value.
+ * @throws MetaDataException if an error occurs.
+ */
+ boolean isRegistered(String namespaceUri) throws MetaDataException;
+
+ /**
+ * @return The registered namespace URIs.
+ * @throws MetaDataException if an error occurs.
+ */
+ String[] getNamespaceUris() throws MetaDataException;
+
+}
diff --git a/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/MetaDataRegistryWrapper.java b/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/MetaDataRegistryWrapper.java
new file mode 100644
index 0000000..17d1ce3
--- /dev/null
+++ b/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/MetaDataRegistryWrapper.java
@@ -0,0 +1,54 @@
+package org.apache.lenya.cms.metadata;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.lenya.cms.repository.metadata.MetaDataException;
+
+public class MetaDataRegistryWrapper implements MetaDataRegistry {
+
+ private org.apache.lenya.cms.repository.metadata.MetaDataRegistry metaDataRegistry;
+
+ private Map<String, ElementSetWrapper> elementSets = new HashMap<String, ElementSetWrapper>();
+
+ public ElementSet getElementSet(String namespaceUri)
+ throws org.apache.lenya.cms.metadata.MetaDataException {
+ ElementSetWrapper wrapper = this.elementSets.get(namespaceUri);
+ if (wrapper == null) {
+ try {
+ wrapper = new ElementSetWrapper(this.metaDataRegistry.getElementSet(namespaceUri));
+ } catch (MetaDataException e) {
+ throw new org.apache.lenya.cms.metadata.MetaDataException(e);
+ }
+ this.elementSets.put(namespaceUri, wrapper);
+ }
+ return wrapper;
+ }
+
+ public String[] getNamespaceUris() throws org.apache.lenya.cms.metadata.MetaDataException {
+ try {
+ return this.metaDataRegistry.getNamespaceUris();
+ } catch (MetaDataException e) {
+ throw new org.apache.lenya.cms.metadata.MetaDataException(e);
+ }
+ }
+
+ public boolean isRegistered(String namespaceUri)
+ throws org.apache.lenya.cms.metadata.MetaDataException {
+ try {
+ return this.metaDataRegistry.isRegistered(namespaceUri);
+ } catch (MetaDataException e) {
+ throw new org.apache.lenya.cms.metadata.MetaDataException(e);
+ }
+ }
+
+ public void setRepositoryMetaDataRegistry(
+ org.apache.lenya.cms.repository.metadata.MetaDataRegistry metaDataRegistry) {
+ this.metaDataRegistry = metaDataRegistry;
+ }
+
+ public org.apache.lenya.cms.repository.metadata.MetaDataRegistry getRepositoryMetaDataRegistry() {
+ return this.metaDataRegistry;
+ }
+
+}
diff --git a/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/MetaDataWrapper.java b/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/MetaDataWrapper.java
new file mode 100644
index 0000000..9ed3a50
--- /dev/null
+++ b/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/MetaDataWrapper.java
@@ -0,0 +1,127 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.lenya.cms.metadata;
+
+import org.apache.lenya.cms.repository.metadata.MetaDataException;
+
+public class MetaDataWrapper implements MetaData {
+
+ private org.apache.lenya.cms.repository.metadata.MetaData delegate;
+
+ public MetaDataWrapper(org.apache.lenya.cms.repository.metadata.MetaData delegate) {
+ this.delegate = delegate;
+ }
+
+ protected org.apache.lenya.cms.repository.metadata.MetaData getDelegate() {
+ return this.delegate;
+ }
+
+ public void addValue(String key, String value)
+ throws org.apache.lenya.cms.metadata.MetaDataException {
+ try {
+ this.delegate.addValue(key, value);
+ } catch (MetaDataException e) {
+ throw new org.apache.lenya.cms.metadata.MetaDataException(e);
+ }
+ }
+
+ public void forcedReplaceBy(MetaData other)
+ throws org.apache.lenya.cms.metadata.MetaDataException {
+ MetaDataWrapper wrapper = (MetaDataWrapper) other;
+ try {
+ this.delegate.forcedReplaceBy(wrapper.getDelegate());
+ } catch (MetaDataException e) {
+ throw new org.apache.lenya.cms.metadata.MetaDataException(e);
+ }
+ }
+
+ public String[] getAvailableKeys() {
+ return this.delegate.getAvailableKeys();
+ }
+
+ private ElementSet elements;
+
+ public ElementSet getElementSet() {
+ if (this.elements == null) {
+ this.elements = new ElementSetWrapper(this.delegate.getElementSet());
+ }
+ return this.elements;
+ }
+
+ public String getFirstValue(String key) throws org.apache.lenya.cms.metadata.MetaDataException {
+ try {
+ return this.delegate.getFirstValue(key);
+ } catch (MetaDataException e) {
+ throw new org.apache.lenya.cms.metadata.MetaDataException(e);
+ }
+ }
+
+ public long getLastModified() throws org.apache.lenya.cms.metadata.MetaDataException {
+ try {
+ return this.delegate.getLastModified();
+ } catch (MetaDataException e) {
+ throw new org.apache.lenya.cms.metadata.MetaDataException(e);
+ }
+ }
+
+ public String[] getPossibleKeys() {
+ return this.delegate.getPossibleKeys();
+ }
+
+ public String[] getValues(String key) throws org.apache.lenya.cms.metadata.MetaDataException {
+ try {
+ return this.delegate.getValues(key);
+ } catch (MetaDataException e) {
+ throw new org.apache.lenya.cms.metadata.MetaDataException(e);
+ }
+ }
+
+ public boolean isValidAttribute(String key) {
+ return this.delegate.isValidAttribute(key);
+ }
+
+ public void removeAllValues(String key) throws org.apache.lenya.cms.metadata.MetaDataException {
+ try {
+ this.delegate.removeAllValues(key);
+ } catch (MetaDataException e) {
+ throw new org.apache.lenya.cms.metadata.MetaDataException(e);
+ }
+
+ }
+
+ public void replaceBy(MetaData other) throws org.apache.lenya.cms.metadata.MetaDataException {
+ try {
+ MetaDataWrapper wrapper = (MetaDataWrapper) other;
+ this.delegate.replaceBy(wrapper.getDelegate());
+ } catch (MetaDataException e) {
+ throw new org.apache.lenya.cms.metadata.MetaDataException(e);
+ }
+
+ }
+
+ public void setValue(String key, String value)
+ throws org.apache.lenya.cms.metadata.MetaDataException {
+ try {
+ this.delegate.setValue(key, value);
+ } catch (MetaDataException e) {
+ throw new org.apache.lenya.cms.metadata.MetaDataException(e);
+ }
+
+ }
+
+}
diff --git a/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/dublincore/DublinCore.java b/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/dublincore/DublinCore.java
new file mode 100644
index 0000000..772c9eb
--- /dev/null
+++ b/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/dublincore/DublinCore.java
@@ -0,0 +1,360 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.lenya.cms.metadata.dublincore;
+
+import org.apache.lenya.cms.metadata.MetaData;
+
+/**
+ * <p>
+ * Dublin core metadata interface.
+ * </p>
+ * <p>
+ * The descriptions are citing the <a href="http://www.dublincore.org">Dublin Core website </a>.
+ * </p>
+ *
+ * @version $Id$
+ */
+public interface DublinCore extends MetaData {
+
+ /**
+ * The dublin core elements namespace.
+ */
+ String DC_NAMESPACE = "http://purl.org/dc/elements/1.1/";
+
+ /**
+ * The dublin core terms namespace.
+ */
+ String DCTERMS_NAMESPACE = "http://purl.org/dc/terms/";
+
+ /**
+ * A name given to the resource. Typically, Title will be a name by which the resource is
+ * formally known.
+ */
+ static final String ELEMENT_TITLE = "title";
+
+ /**
+ * An entity primarily responsible for making the content of the resource. Examples of Creator
+ * include a person, an organization, or a service. Typically, the name of a Creator should be
+ * used to indicate the entity.
+ */
+ static final String ELEMENT_CREATOR = "creator";
+
+ /**
+ * A topic of the content of the resource. Typically, Subject will be expressed as keywords, key
+ * phrases or classification codes that describe a topic of the resource. Recommended best
+ * practice is to select a value from a controlled vocabulary or formal classification scheme.
+ */
+ static final String ELEMENT_SUBJECT = "subject";
+
+ /**
+ * An account of the content of the resource. Examples of Description include, but is not
+ * limited to: an abstract, table of contents, reference to a graphical representation of
+ * content or a free-text account of the content.
+ */
+ static final String ELEMENT_DESCRIPTION = "description";
+
+ /**
+ * An entity responsible for making the resource available. Examples of Publisher include a
+ * person, an organization, or a service. Typically, the name of a Publisher should be used to
+ * indicate the entity.
+ */
+ static final String ELEMENT_PUBLISHER = "publisher";
+
+ /**
+ * An entity responsible for making contributions to the content of the resource. Examples of
+ * Contributor include a person, an organization, or a service. Typically, the name of a
+ * Contributor should be used to indicate the entity.
+ */
+ static final String ELEMENT_CONTRIBUTOR = "contributor";
+
+ /**
+ * A date of an event in the lifecycle of the resource. Typically, Date will be associated with
+ * the creation or availability of the resource. Recommended best practice for encoding the date
+ * value is defined in a profile of ISO 8601 [W3CDTF] and includes (among others) dates of the
+ * form YYYY-MM-DD.
+ */
+ static final String ELEMENT_DATE = "date";
+
+ /**
+ * The nature or genre of the content of the resource. Type includes terms describing general
+ * categories, functions, genres, or aggregation levels for content. Recommended best practice
+ * is to select a value from a controlled vocabulary (for example, the DCMI Type Vocabulary
+ * [DCT1]). To describe the physical or digital manifestation of the resource, use the FORMAT
+ * element.
+ */
+ static final String ELEMENT_TYPE = "type";
+
+ /**
+ * The physical or digital manifestation of the resource. Typically, Format may include the
+ * media-type or dimensions of the resource. Format may be used to identify the software,
+ * hardware, or other equipment needed to display or operate the resource. Examples of
+ * dimensions include size and duration. Recommended best practice is to select a value from a
+ * controlled vocabulary (for example, the list of Internet Media Types [MIME] defining computer
+ * media formats).
+ */
+ static final String ELEMENT_FORMAT = "format";
+
+ /**
+ * An unambiguous reference to the resource within a given context. Recommended best practice is
+ * to identify the resource by means of a string or number conforming to a formal identification
+ * system. Formal identification systems include but are not limited to the Uniform Resource
+ * Identifier (URI) (including the Uniform Resource Locator (URL)), the Digital Object
+ * Identifier (DOI) and the International Standard Book Number (ISBN).
+ */
+ static final String ELEMENT_IDENTIFIER = "identifier";
+
+ /**
+ * A Reference to a resource from which the present resource is derived. The present resource
+ * may be derived from the Source resource in whole or in part. Recommended best practice is to
+ * identify the referenced resource by means of a string or number conforming to a formal
+ * identification system.
+ */
+ static final String ELEMENT_SOURCE = "source";
+
+ /**
+ * A language of the intellectual content of the resource. Recommended best practice is to use
+ * RFC 3066 [RFC3066] which, in conjunction with ISO639 [ISO639]), defines two- and three-letter
+ * primary language tags with optional subtags. Examples include "en" or "eng" for English,
+ * "akk" for Akkadian", and "en-GB" for English used in the United Kingdom.
+ */
+ static final String ELEMENT_LANGUAGE = "language";
+
+ /**
+ * A reference to a related resource. Recommended best practice is to identify the referenced
+ * resource by means of a string or number conforming to a formal identification system.
+ */
+ static final String ELEMENT_RELATION = "relation";
+
+ /**
+ * The extent or scope of the content of the resource. Typically, Coverage will include spatial
+ * location (a place name or geographic coordinates), temporal period (a period label, date, or
+ * date range) or jurisdiction (such as a named administrative entity). Recommended best
+ * practice is to select a value from a controlled vocabulary (for example, the Thesaurus of
+ * Geographic Names [TGN]) and to use, where appropriate, named places or time periods in
+ * preference to numeric identifiers such as sets of coordinates or date ranges.
+ */
+ static final String ELEMENT_COVERAGE = "coverage";
+
+ /**
+ * Information about rights held in and over the resource. Typically, Rights will contain a
+ * rights management statement for the resource, or reference a service providing such
+ * information. Rights information often encompasses Intellectual Property Rights (IPR),
+ * Copyright, and various Property Rights. If the Rights element is absent, no assumptions may
+ * be made about any rights held in or over the resource.
+ */
+ static final String ELEMENT_RIGHTS = "rights";
+
+ /**
+ * A summary of the content of the resource.
+ */
+ static final String TERM_ABSTRACT = "abstract";
+
+ /**
+ * Information about who can access the resource or an indication of its security status. Access
+ * Rights may include information regarding access or restrictions based on privacy, security or
+ * other regulations.
+ */
+ static final String TERM_ACCESSRIGHTS = "accessRights";
+
+ /**
+ * Any form of the title used as a substitute or alternative to the formal title of the
+ * resource. This qualifier can include Title abbreviations as well as translations.
+ */
+ static final String TERM_ALTERNATIVE = "alternative";
+
+ /**
+ * A class of entity for whom the resource is intended or useful. A class of entity may be
+ * determined by the creator or the publisher or by a third party.
+ */
+ static final String TERM_AUDIENCE = "audience";
+
+ /**
+ * Date (often a range) that the resource will become or did become available.
+ */
+ static final String TERM_AVAILABLE = "available";
+
+ /**
+ * A bibliographic reference for the resource. Recommended practice is to include sufficient
+ * bibliographic detail to identify the resource as unambiguously as possible, whether or not
+ * the citation is in a standard form.
+ */
+ static final String TERM_BIBLIOGRAPHICCITATION = "bibliographicCitation";
+
+ /**
+ * A reference to an established standard to which the resource conforms.
+ */
+ static final String TERM_CONFORMSTO = "conformsTo";
+
+ /**
+ * Date of creation of the resource.
+ */
+ static final String TERM_CREATED = "created";
+
+ /**
+ * Date of acceptance of the resource (e.g. of thesis by university department, of article by
+ * journal, etc.).
+ */
+ static final String TERM_DATEACCEPTED = "dateAccepted";
+
+ /**
+ * Date of a statement of copyright.
+ */
+ static final String TERM_DATECOPYRIGHTED = "dateCopyrighted";
+
+ /**
+ * Date of submission of the resource (e.g. thesis, articles, etc.).
+ */
+ static final String TERM_DATESUBMITTED = "dateSubmitted";
+
+ /**
+ * A general statement describing the education or training context. Alternatively, a more
+ * specific statement of the location of the audience in terms of its progression through an
+ * education or training context.
+ */
+ static final String TERM_EDUCATIONLEVEL = "educationLevel";
+
+ /**
+ * The size or duration of the resource.
+ */
+ static final String TERM_EXTENT = "extent";
+
+ /**
+ * The described resource pre-existed the referenced resource, which is essentially the same
+ * intellectual content presented in another format.
+ */
+ static final String TERM_HASFORMAT = "hasFormat";
+
+ /**
+ * The described resource includes the referenced resource either physically or logically.
+ */
+ static final String TERM_HASPART = "hasPart";
+
+ /**
+ * The described resource has a version, edition, or adaptation, namely, the referenced
+ * resource.
+ */
+ static final String TERM_HASVERSION = "hasVersion";
+
+ /**
+ * The described resource is the same intellectual content of the referenced resource, but
+ * presented in another format.
+ */
+ static final String TERM_ISFORMATOF = "isFormatOf";
+
+ /**
+ * The described resource is a physical or logical part of the referenced resource.
+ */
+ static final String TERM_ISPARTOF = "isPartOf";
+
+ /**
+ * The described resource is referenced, cited, or otherwise pointed to by the referenced
+ * resource.
+ */
+ static final String TERM_ISREFERENCEDBY = "isReferencedBy";
+
+ /**
+ * The described resource is supplanted, displaced, or superseded by the referenced resource.
+ */
+ static final String TERM_ISREPLACEDBY = "isReplacedBy";
+
+ /**
+ * The described resource is required by the referenced resource, either physically or
+ * logically.
+ */
+ static final String TERM_ISREQUIREDBY = "isRequiredBy";
+
+ /**
+ * Date of formal issuance (e.g., publication) of the resource.
+ */
+ static final String TERM_ISSUED = "issued";
+
+ /**
+ * The described resource is a version, edition, or adaptation of the referenced resource.
+ * Changes in version imply substantive changes in content rather than differences in format.
+ */
+ static final String TERM_ISVERSIONOF = "isVersionOf";
+
+ /**
+ * A legal document giving official permission to do something with the resource. Recommended
+ * best practice is to identify the license using a URI. Examples of such licenses can be found
+ * at http://creativecommons.org/licenses/.
+ */
+ static final String TERM_LICENSE = "license";
+
+ /**
+ * A class of entity that mediates access to the resource and for whom the resource is intended
+ * or useful. The audiences for a resource are of two basic classes: (1) an ultimate beneficiary
+ * of the resource, and (2) frequently, an entity that mediates access to the resource. The
+ * mediator element refinement represents the second of these two classes.
+ */
+ static final String TERM_MEDIATOR = "mediator";
+
+ /**
+ * The material or physical carrier of the resource.
+ */
+ static final String TERM_MEDIUM = "medium";
+
+ /**
+ * Date on which the resource was changed.
+ */
+ static final String TERM_MODIFIED = "modified";
+
+ /**
+ * The described resource references, cites, or otherwise points to the referenced resource.
+ */
+ static final String TERM_REFERENCES = "references";
+
+ /**
+ * The described resource supplants, displaces, or supersedes the referenced resource.
+ */
+ static final String TERM_REPLACES = "replaces";
+
+ /**
+ * The described resource requires the referenced resource to support its function, delivery, or
+ * coherence of content.
+ */
+ static final String TERM_REQUIRES = "requires";
+
+ /**
+ * A person or organization owning or managing rights over the resource. Recommended best
+ * practice is to use the URI or name of the Rights Holder to indicate the entity.
+ */
+ static final String TERM_RIGHTSHOLDER = "rightsHolder";
+
+ /**
+ * Spatial characteristics of the intellectual content of the resource.
+ */
+ static final String TERM_SPATIAL = "spatial";
+
+ /**
+ * A list of subunits of the content of the resource.
+ */
+ static final String TERM_TABLEOFCONTENTS = "tableOfContents";
+
+ /**
+ * Temporal characteristics of the intellectual content of the resource.
+ */
+ static final String TERM_TEMPORAL = "temporal";
+
+ /**
+ * Date (often a range) of validity of a resource.
+ */
+ static final String TERM_VALID = "valid";
+
+}
diff --git a/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/dublincore/DublinCoreHelper.java b/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/dublincore/DublinCoreHelper.java
new file mode 100644
index 0000000..deb9fe6
--- /dev/null
+++ b/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/dublincore/DublinCoreHelper.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.lenya.cms.metadata.dublincore;
+
+import org.apache.lenya.cms.metadata.MetaData;
+import org.apache.lenya.cms.metadata.MetaDataException;
+import org.apache.lenya.cms.metadata.MetaDataOwner;
+import org.apache.lenya.cms.publication.Document;
+
+/**
+ * Helper class to access dublin core meta data.
+ */
+public class DublinCoreHelper {
+
+ /**
+ * @param owner The owner.
+ * @return The dublin core title or <code>null</code> if the title is not set.
+ * @throws MetaDataException if the owner has no dublin core meta data.
+ */
+ public static String getTitle(MetaDataOwner owner) throws MetaDataException {
+ return getDublinCore(owner).getFirstValue(DublinCore.ELEMENT_TITLE);
+ }
+
+ /**
+ * @param doc The document.
+ * @param fallbackToUuid If the dublin core title is <code>null</code>, the document's UUID is returned.
+ * @return The dublin core title.
+ * @throws MetaDataException if the document has no dublin core meta data.
+ */
+ public static String getTitle(Document doc, boolean fallbackToUuid) throws MetaDataException {
+ String title = DublinCoreHelper.getTitle(doc);
+ return title == null ? doc.getUUID() : title;
+ }
+
+ protected static MetaData getDublinCore(MetaDataOwner owner) throws MetaDataException {
+ return owner.getMetaData(DublinCore.DC_NAMESPACE);
+ }
+
+}
diff --git a/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/usecases/Metadata.java b/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/usecases/Metadata.java
new file mode 100644
index 0000000..fddbff6
--- /dev/null
+++ b/org.apache.lenya.core.metadata/src/main/java/org/apache/lenya/cms/metadata/usecases/Metadata.java
@@ -0,0 +1,158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ *
+ */
+package org.apache.lenya.cms.metadata.usecases;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.lenya.cms.metadata.Element;
+import org.apache.lenya.cms.metadata.MetaData;
+import org.apache.lenya.cms.metadata.MetaDataRegistry;
+import org.apache.lenya.cms.publication.Document;
+import org.apache.lenya.cms.publication.Node;
+import org.apache.lenya.cms.site.usecases.SiteUsecase;
+import org.apache.lenya.cms.usecase.UsecaseException;
+import org.apache.lenya.cms.workflow.WorkflowUtil;
+
+/**
+ * Usecase to edit metadata for a resource.
+ *
+ * @version $Id$
+ */
+public class Metadata extends SiteUsecase {
+
+ private MetaDataRegistry metaDataRegistry;
+
+ /**
+ * @see org.apache.lenya.cms.usecase.AbstractUsecase#getNodesToLock()
+ */
+ protected Node[] getNodesToLock() throws UsecaseException {
+ Node[] objects = new Node[0];
+ if(getSourceDocument() != null) {
+ objects = new Node[] { getSourceDocument() };
+ }
+ return objects;
+ }
+
+ /**
+ * Object to pass a meta data entry to the view.
+ */
+ public static class MetaDataWrapper {
+
+ private String[] values;
+ private Element element;
+ private boolean editable;
+
+ /**
+ * @param element The element.
+ * @param values The values for the element.
+ * @param canChange If the element value can be changed via the GUI. A <code>true</code>
+ * value is only effective if the element itself is editable.
+ */
+ public MetaDataWrapper(Element element, String[] values, boolean canChange) {
+ this.values = values;
+ this.element = element;
+ this.editable = element.isEditable() && canChange;
+ }
+
+ /**
+ * @return The values for the element.
+ */
+ public String[] getValues() {
+ return this.values;
+ }
+
+ /**
+ * @return The element.
+ */
+ public Element getElement() {
+ return this.element;
+ }
+
+ /**
+ * @return If the value can be changed via the GUI.
+ */
+ public boolean isEditable() {
+ return this.editable;
+ }
+
+ }
+
+ /**
+ * @see org.apache.lenya.cms.usecase.AbstractUsecase#initParameters()
+ */
+ protected void initParameters() {
+ super.initParameters();
+
+ Document doc = getSourceDocument();
+ if (doc == null) {
+ return;
+ }
+
+
+ try {
+ boolean canChange = WorkflowUtil.canInvoke(doc, "edit");
+
+ if (!canChange) {
+ addInfoMessage("cannot-change-metadata");
+ }
+
+ List numbers = new ArrayList();
+ Map num2namespace = new HashMap();
+ List keyList = new ArrayList();
+
+ String[] namespaces = getMetaDataRegistry().getNamespaceUris();
+
+ for (int nsIndex = 0; nsIndex < namespaces.length; nsIndex++) {
+ MetaData meta = doc.getMetaData(namespaces[nsIndex]);
+ String[] keys = meta.getPossibleKeys();
+ for (int keyIndex = 0; keyIndex < keys.length; keyIndex++) {
+ String key = "ns" + nsIndex + "." + keys[keyIndex];
+ String[] values = meta.getValues(keys[keyIndex]);
+ Element element = meta.getElementSet().getElement(keys[keyIndex]);
+ setParameter(key, new MetaDataWrapper(element, values, canChange));
+ keyList.add(key);
+ }
+ numbers.add("" + nsIndex);
+ num2namespace.put("" + nsIndex, namespaces[nsIndex]);
+ }
+
+ setParameter("numbers", numbers);
+ setParameter("namespaces", num2namespace);
+
+ Collections.sort(keyList);
+ setParameter("keys", keyList);
+
+ } catch (Exception e) {
+ getLogger().error("Unable to load meta data.", e);
+ addErrorMessage("Unable to load meta data: " + e.getMessage());
+ }
+ }
+
+ protected MetaDataRegistry getMetaDataRegistry() {
+ return metaDataRegistry;
+ }
+
+ public void setMetaDataRegistry(MetaDataRegistry metaDataRegistry) {
+ this.metaDataRegistry = metaDataRegistry;
+ }
+
+}