diff --git a/extension/restconfig/src/main/java/org/geoserver/catalog/rest/AbstractCatalogListResource.java b/extension/restconfig/src/main/java/org/geoserver/catalog/rest/AbstractCatalogListResource.java index efe2d78..541db32 100644 --- a/extension/restconfig/src/main/java/org/geoserver/catalog/rest/AbstractCatalogListResource.java +++ b/extension/restconfig/src/main/java/org/geoserver/catalog/rest/AbstractCatalogListResource.java @@ -4,12 +4,18 @@ */ package org.geoserver.catalog.rest; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import org.geoserver.catalog.Catalog; import org.geoserver.config.util.XStreamPersister; import org.geoserver.ows.util.OwsUtils; +import org.geoserver.rest.format.ReflectiveJSONFormat; +import org.geoserver.rest.format.ReflectiveXMLFormat; import org.restlet.Context; import org.restlet.data.Request; import org.restlet.data.Response; @@ -36,16 +42,54 @@ public abstract class AbstractCatalogListResource extends CatalogResourceBase { protected abstract Collection handleListGet() throws Exception; + //JD: we create custom formats here because we need to set up the collection aliases + // correctly, basically whatever collection we get back we ant to alias to layers, featureTypes, + // coverages, styles, etc... + @Override + protected ReflectiveJSONFormat createJSONFormat(Request request, Response response) { + final ReflectiveJSONFormat f = super.createJSONFormat(request, response); + return new ReflectiveJSONFormat() { + @Override + public XStream getXStream() { + return f.getXStream(); + } + + @Override + protected void write(Object data, OutputStream output) throws IOException { + aliasCollection(data, f.getXStream()); + f.getXStream().toXML(data, output); + } + }; + } + + @Override + protected ReflectiveXMLFormat createXMLFormat(Request request, Response response) { + final ReflectiveXMLFormat f = super.createXMLFormat(request, response); + return new ReflectiveXMLFormat() { + @Override + public XStream getXStream() { + return f.getXStream(); + } + + @Override + protected void write(Object data, OutputStream output) throws IOException { + aliasCollection(data, f.getXStream()); + f.getXStream().toXML(data, output); + } + }; + } + @Override protected void configureXStream(XStream xstream) { XStreamPersister xp = xpf.createXMLPersister(); final String name = xp.getClassAliasingMapper().serializedClass( clazz ); - xstream.alias( name, clazz ); - aliasCollection( name + "s", xstream ); xstream.registerConverter( new CollectionConverter(xstream.getMapper()) { + public boolean canConvert(Class type) { + return Collection.class.isAssignableFrom(type); + }; @Override protected void writeItem(Object item, MarshallingContext context, @@ -100,7 +144,9 @@ public abstract class AbstractCatalogListResource extends CatalogResourceBase { * to work with a Set. *
*/ - protected void aliasCollection( String alias, XStream xstream ) { - xstream.alias( alias, Collection.class, ArrayList.class); + protected void aliasCollection( Object data, XStream xstream ) { + XStreamPersister xp = xpf.createXMLPersister(); + final String alias = xp.getClassAliasingMapper().serializedClass( clazz ); + xstream.alias(alias + "s", Collection.class, data.getClass()); } } diff --git a/extension/restconfig/src/main/java/org/geoserver/catalog/rest/StyleListResource.java b/extension/restconfig/src/main/java/org/geoserver/catalog/rest/StyleListResource.java index f80cb75..959c374 100644 --- a/extension/restconfig/src/main/java/org/geoserver/catalog/rest/StyleListResource.java +++ b/extension/restconfig/src/main/java/org/geoserver/catalog/rest/StyleListResource.java @@ -5,7 +5,6 @@ package org.geoserver.catalog.rest; import java.util.Collection; -import java.util.HashSet; import org.geoserver.catalog.Catalog; import org.geoserver.catalog.StyleInfo; @@ -13,8 +12,6 @@ import org.restlet.Context; import org.restlet.data.Request; import org.restlet.data.Response; -import com.thoughtworks.xstream.XStream; - public class StyleListResource extends AbstractCatalogListResource { protected StyleListResource(Context context, Request request, @@ -22,22 +19,7 @@ public class StyleListResource extends AbstractCatalogListResource { super(context, request, response, StyleInfo.class, catalog); } - - @Override - protected void aliasCollection(String alias, XStream xstream) { - //JD: this is a bit of hack, we check when we alias as to - // property alias the correct collection type, since in teh case - // of listing all, a List is returned, but when referencing through - // style, a Set is returned - String layer = getAttribute("layer"); - if ( layer == null ) { - super.aliasCollection(alias, xstream); - } - else { - xstream.alias( alias, Collection.class, HashSet.class ); - } - } - + @Override protected Collection handleListGet() throws Exception { String layer = getAttribute("layer"); diff --git a/extension/restconfig/src/test/java/org/geoserver/catalog/rest/LayerGroupTest.java b/extension/restconfig/src/test/java/org/geoserver/catalog/rest/LayerGroupTest.java index d2eb79c..db3d647 100644 --- a/extension/restconfig/src/test/java/org/geoserver/catalog/rest/LayerGroupTest.java +++ b/extension/restconfig/src/test/java/org/geoserver/catalog/rest/LayerGroupTest.java @@ -40,6 +40,7 @@ public class LayerGroupTest extends CatalogRESTTestSupport { } public void testGetAsXML() throws Exception { + print(get("/rest/layergroups/sfLayerGroup.xml")); Document dom = getAsDOM( "/rest/layergroups/sfLayerGroup.xml"); assertEquals( "layerGroup", dom.getDocumentElement().getNodeName() ); assertXpathEvaluatesTo("sfLayerGroup", "/layerGroup/name", dom ); diff --git a/extension/restconfig/src/test/java/org/geoserver/catalog/rest/StyleTest.java b/extension/restconfig/src/test/java/org/geoserver/catalog/rest/StyleTest.java index 0e195e7..83f5f7f 100644 --- a/extension/restconfig/src/test/java/org/geoserver/catalog/rest/StyleTest.java +++ b/extension/restconfig/src/test/java/org/geoserver/catalog/rest/StyleTest.java @@ -33,6 +33,7 @@ public class StyleTest extends CatalogRESTTestSupport { public void testGetAllASJSON() throws Exception { JSON json = getAsJSON("/rest/styles.json"); + List+ * This method does not remove the object from the catalog, it "unnattaches" the object + * resolving any proxies. + *
+ *+ * In the even the specified object does not exist in the catalog it itself should be returned, + * this method should never return null. + *
+ */ +* clazz is used to determine the implementation of StoreInfo @@ -595,6 +616,19 @@ public interface Catalog extends CatalogInfo { void save(ResourceInfo resource); /** + * Detatches the resource from the catalog. + *
+ * This method does not remove the object from the catalog, it "unnattaches" the object + * resolving any proxies. + *
+ *+ * In the even the specified object does not exist in the catalog it itself should be returned, + * this method should never return null. + *
+ */ +* The clazz parameter is used to filter the types of resources @@ -1009,6 +1043,19 @@ public interface Catalog extends CatalogInfo { void save(LayerInfo layer); /** + * Detatches the layer from the catalog. + *
+ * This method does not remove the object from the catalog, it "unnattaches" the object + * resolving any proxies. + *
+ *+ * In the even the specified object does not exist in the catalog it itself should be returned, + * this method should never return null. + *
+ */ + LayerInfo detach(LayerInfo layer); + + /** * All coverages which are part of the specified store. */ List+ * This method does not remove the object from the catalog, it "unnattaches" the object + * resolving any proxies. + *
+ *+ * In the even the specified object does not exist in the catalog it itself should be returned, + * this method should never return null. + *
+ */ + MapInfo detach(MapInfo map); /** * All maps in the catalog. @@ -1112,6 +1172,19 @@ public interface Catalog extends CatalogInfo { void save(LayerGroupInfo layerGroup); /** + * Detatches the layer group from the catalog. + *+ * This method does not remove the object from the catalog, it "unnattaches" the object + * resolving any proxies. + *
+ *+ * In the even the specified object does not exist in the catalog it itself should be returned, + * this method should never return null. + *
+ */ + LayerGroupInfo detach(LayerGroupInfo layerGroup); + + /** * All layer groups in the catalog. */ List+ * This method does not remove the object from the catalog, it "unnattaches" the object + * resolving any proxies. + *
+ *+ * In the even the specified object does not exist in the catalog it itself should be returned, + * this method should never return null. + *
+ */ + StyleInfo detach(StyleInfo style); + + /** * Returns the style matching a particular id, ornull if no
* such style could be found.
*/
@@ -1185,6 +1271,19 @@ public interface Catalog extends CatalogInfo {
void save(NamespaceInfo namespace);
/**
+ * Detatches the namespace from the catalog.
+ * + * This method does not remove the object from the catalog, it "unnattaches" the object + * resolving any proxies. + *
+ *+ * In the even the specified object does not exist in the catalog it itself should be returned, + * this method should never return null. + *
+ */ + NamespaceInfo detach(NamespaceInfo namespace); + + /** * Returns the namespace matching the specified id. * */ @@ -1246,6 +1345,19 @@ public interface Catalog extends CatalogInfo { void save(WorkspaceInfo workspace); /** + * Detatches the workspace from the catalog. + *+ * This method does not remove the object from the catalog, it "unnattaches" the object + * resolving any proxies. + *
+ *+ * In the even the specified object does not exist in the catalog it itself should be returned, + * this method should never return null. + *
+ */ + WorkspaceInfo detach(WorkspaceInfo workspace); + + /** * The default workspace for the catalog. */ WorkspaceInfo getDefaultWorkspace(); @@ -1277,7 +1389,7 @@ public interface Catalog extends CatalogInfo { * @param The name of the store, or null or {@link #DEFAULT} to get the default workspace */ WorkspaceInfo getWorkspaceByName( String name ); - + /** * catalog listeners. * @@ -1295,6 +1407,43 @@ public interface Catalog extends CatalogInfo { void removeListener(CatalogListener listener); /** + * Fires the event for an object being added to the catalog. + *+ * This method should not be called by client code. It is meant to be called + * interally by the catalog subsystem. + *
+ */ + void fireAdded(CatalogInfo object); + + /** + * Fires the event for an object being modified in the catalog. + *+ * This method should not be called by client code. It is meant to be called + * interally by the catalog subsystem. + *
+ */ + void fireModified(CatalogInfo object, List+ * This method should not be called by client code. It is meant to be called + * interally by the catalog subsystem. + *
+ */ + void firePostModified(CatalogInfo object); + + /** + * Fires the event for an object being removed from the catalog. + *+ * This method should not be called by client code. It is meant to be called + * interally by the catalog subsystem. + *
+ */ + void fireRemoved(CatalogInfo object); + + /** * Returns the pool or cache for resources. ** This object is used to load physical resources like data stores, feature diff --git a/main/src/main/java/org/geoserver/catalog/CatalogBuilder.java b/main/src/main/java/org/geoserver/catalog/CatalogBuilder.java index 2c8bb61..28a6f09 100644 --- a/main/src/main/java/org/geoserver/catalog/CatalogBuilder.java +++ b/main/src/main/java/org/geoserver/catalog/CatalogBuilder.java @@ -252,64 +252,7 @@ public class CatalogBuilder { *
*/+ * DAO implementations are responsible for triggering a {@link CatalogModifyEvent} by calling + * {@link Catalog#fireModified(CatalogInfo, List, List, List)}. This is the responsibility of + * the dao because it is best suited to knowing and tracking which attributes of the object have + * changed. + *
+ */ + void save(StoreInfo store); + + /** + * Detaches a store from the underlying persistence layer. + *+ * "Detaching" is specific to the underlying storage engine. But in general when an object + * is detached any proxies or uninitialized state of the object should be resolved. + *
+ * + * @see Catalog#detach(StoreInfo) + */ ++ * The clazz parameter is used to type narrow the returned object to a + * specific type of store. If the type of store is unknown the client may simply + * specify StoreInfo.class. The dao should still create the correct type of store. + *
+ * @param id The unique identifier of the store + * @param clazz The class of the store. + * + * @return The store, ornull if no such store exists.
+ */
+ + * The clazz parameter is used to type narrow the returned object to a + * specific type of store. If the type of store is unknown the client may simply + * specify StoreInfo.class. The dao should still create the correct type of store. + *
+ * @param workspace THe containing workspace of the store. + * @param name The name of the store. + * @param clazz The class of the store. + * + * @return The store, ornull if no such store exists.
+ */
+ + * The clazz parameter is used to type narrow/filter the returned objects + * to a specific type of store. Specifying StoreInfo.class will return all types of + * stores. + *
+ * @param workspace The containing workspace. + * @param clazz The class of the stores to return. + * + * @return A list of stores, possibly empty. + */ ++ * The clazz parameter is used to type narrow/filter the returned objects + * to a specific type of store. Specifying StoreInfo.class will return all types of + * stores. + *
+ * + * @param clazz The class of the stores to return. + * + * @return A list of stores, possibly empty. + */ ++ * DAO implementations are responsible for triggering a {@link CatalogModifyEvent} by calling + * {@link Catalog#fireModified(CatalogInfo, List, List, List)}. The source of the event is the + * workspace itself and changed property is "defaultDataStore". The changed old/new values should + * the old/new datastores respectively. + *
+ * @param workspace The workspace. + * @param store The default data store. + */ + void setDefaultDataStore(WorkspaceInfo workspace, DataStoreInfo store); + + // + // Resources + // + /** + * Adds a resource to persistent storage. + */ + ResourceInfo add(ResourceInfo resource); + + /** + * Removes a resource from persistent storage. + */ + void remove(ResourceInfo resource); + + /** + * Persists any modifications to a resource to persistent storage. + *+ * DAO implementations are responsible for triggering a {@link CatalogModifyEvent} by calling + * {@link Catalog#fireModified(CatalogInfo, List, List, List)}. This is the responsibility of + * the dao because it is best suited to knowing and tracking which attributes of the object have + * changed. + *
+ */ + void save(ResourceInfo resource); + + /** + * Detaches a resource from the underlying persistence layer. + *+ * "Detaching" is specific to the underlying storage engine. But in general when an object + * is detached any proxies or uninitialized state of the object should be resolved. + *
+ * + * @see Catalog#detach(ResourceInfo) + */ ++ * The clazz parameter is used to type narrow the returned object to a + * specific type of resource. If the type of resource is unknown the client may simply + * specify ResourceInfo.class. The dao should still create the correct type of resource. + *
+ * @param id The unique identifier of the resource + * @param clazz The class of the resource. + * + * @return The resource, ornull if no such store exists.
+ */
+ + * The clazz parameter is used to type narrow the returned object to a + * specific type of resource. If the type of resource is unknown the client may simply + * specify ResourceInfo.class. The dao should still create the correct type of resource. + *
+ * @param namespace The namespace of the resource + * @param name The local name of the resource + * @param clazz The class of the resource + * + * @return The resource, ornull if no such store exists.
+ */
+ + * The clazz parameter is used to type narrow/filter the returned objects + * to a specific type of store. Specifying StoreInfo.class will return all types of + * stores. + *
+ * + * @param clazz The class of the resources to return. + * + * @return A list of resources, possibly empty. + */ ++ * The clazz parameter is used to type narrow/filter the returned objects + * to a specific type of store. Specifying StoreInfo.class will return all types of + * stores. + *
+ * + * @param namespace The namespace of resources + * @param clazz The class of the resources to return. + * + * @return A list of resources, possibly empty. + */ ++ * The clazz parameter is used to type narrow the returned object to a + * specific type of resource. If the type of resource is unknown the client may simply + * specify ResourceInfo.class. The dao should still create the correct type of resource. + *
+ * @param store The containing store + * @param name The local name of the resource + * @param clazz The class of the resource + * + * @return The resource, ornull if no such store exists.
+ */
+ + * The clazz parameter is used to type narrow/filter the returned objects + * to a specific type of store. Specifying StoreInfo.class will return all types of + * stores. + *
+ * + * @param store The containing store + * @param clazz The class of the resources to return + * + * @return A list of resources, possibly empty. + */ ++ * DAO implementations are responsible for triggering a {@link CatalogModifyEvent} by calling + * {@link Catalog#fireModified(CatalogInfo, List, List, List)}. This is the responsibility of + * the dao because it is best suited to knowing and tracking which attributes of the object have + * changed. + *
+ */ + void save(LayerInfo layer); + + /** + * Detaches a layer from the underlying persistence layer. + *+ * "Detaching" is specific to the underlying storage engine. But in general when an object + * is detached any proxies or uninitialized state of the object should be resolved. + *
+ * + * @see Catalog#detach(LayerInfo) + */ + LayerInfo detach(LayerInfo layer); + + /** + * Loads a layer from persistent storage by specifying its identifier. + * + * @param id The unique identifier of the layer + * + * @return The layer, ornull if no such layer exists.
+ */
+ LayerInfo getLayer(String id);
+
+ /**
+ * Loads a layer from persistent storage by specifying its name.
+ *
+ * @param name The name of the layer
+ *
+ * @return The layer, or null if no such layer exists.
+ */
+ LayerInfo getLayerByName(String name);
+
+ /**
+ * Loads all layers from persistent storage that publish a specified resource.
+ *
+ * @param resource The published resource
+ *
+ * @return List of layers, possibly empty
+ */
+ List+ * DAO implementations are responsible for triggering a {@link CatalogModifyEvent} by calling + * {@link Catalog#fireModified(CatalogInfo, List, List, List)}. This is the responsibility of + * the dao because it is best suited to knowing and tracking which attributes of the object have + * changed. + *
+ */ + void save(MapInfo map); + + /** + * Detaches a map from the underlying persistence layer. + *+ * "Detaching" is specific to the underlying storage engine. But in general when an object + * is detached any proxies or uninitialized state of the object should be resolved. + *
+ * + * @see Catalog#detach(MapInfo) + */ + MapInfo detach(MapInfo map); + + /** + * Loads a map from persistent storage by its identifier. + * + * @param id The unique identifier of the map + * + * @return The map, ornull if no such map exists
+ */
+ MapInfo getMap(String id);
+
+ /**
+ * Loads a map from persistent storage by its name.
+ *
+ * @param name The name of the map
+ *
+ * @return The map, or null if no such map exists
+ */
+ MapInfo getMapByName(String name);
+
+ /**
+ * Lists all maps from persistent storage.
+ *
+ * @return A list of maps, possibly empty
+ */
+ List+ * DAO implementations are responsible for triggering a {@link CatalogModifyEvent} by calling + * {@link Catalog#fireModified(CatalogInfo, List, List, List)}. This is the responsibility of + * the dao because it is best suited to knowing and tracking which attributes of the object have + * changed. + *
+ */ + void save(LayerGroupInfo layerGroup); + + /** + * Detaches a layer group from the underlying persistence layer. + *+ * "Detaching" is specific to the underlying storage engine. But in general when an object + * is detached any proxies or uninitialized state of the object should be resolved. + *
+ * + * @see Catalog#detach(LayerGroupInfo) + */ + LayerGroupInfo detach(LayerGroupInfo layerGroup); + + /** + * Loads a layer group from persistent storage by specifying its identifier. + * + * @param id The unique identifier for the layer group + * + * @return The layer group, ornull if it does not exist
+ */
+ LayerGroupInfo getLayerGroup(String id);
+
+ /**
+ * Loads a layer group from persistent storage by specifying its name.
+ *
+ * @param name The name of the layer group.
+ *
+ * @return The layer group, or null getLayerGroups();
+
+ //
+ // Namespaces
+ //
+ /**
+ * Adds a namespace to persistent storage.
+ */
+ NamespaceInfo add(NamespaceInfo namespace);
+
+ /**
+ * Removes a namespace from persistent storage.
+ */
+ void remove(NamespaceInfo namespace);
+
+ /**
+ * Persists any modifications to a namespace to persistent storage.
+ *
+ * DAO implementations are responsible for triggering a {@link CatalogModifyEvent} by calling
+ * {@link Catalog#fireModified(CatalogInfo, List, List, List)}. This is the responsibility of
+ * the dao because it is best suited to knowing and tracking which attributes of the object have
+ * changed.
+ *
+ */
+ void save(NamespaceInfo namespace);
+
+ /**
+ * Detaches a namespace from the underlying persistence layer.
+ *
+ * "Detaching" is specific to the underlying storage engine. But in general when an object
+ * is detached any proxies or uninitialized state of the object should be resolved.
+ *
+ *
+ * @see Catalog#detach(NamespaceInfo)
+ */
+ NamespaceInfo detach(NamespaceInfo namespace);
+
+ /**
+ * Loads the default namespace from persistent storage.
+ *
+ * @return The namespace, or null if there is no default namespace set
+ */
+ NamespaceInfo getDefaultNamespace();
+
+ /**
+ * Sets the default namespace.
+ *
+ * DAO implementations are responsible for triggering a {@link CatalogModifyEvent} by calling
+ * {@link Catalog#fireModified(CatalogInfo, List, List, List)}. The source of the event is the
+ * catalog itself and changed property is "defaultNamespace". The changed old/new values should
+ * the old/new namespaces respectively.
+ *
+ */
+ void setDefaultNamespace(NamespaceInfo defaultNamespace);
+
+ /**
+ * Loads a namespace from persistent storage by specifying its identifier.
+ *
+ * @param id The unique identifier of the namespace.
+ *
+ * @return The namespace, or null if no such namespace exists
+ */
+ NamespaceInfo getNamespace(String id);
+
+ /**
+ * Loads a namespace from persistent storage by specifying its prefix.
+ *
+ * @param prefix The prefix of the namespace.
+ *
+ * @return The namespace, or null if no such namespace exists
+ */
+ NamespaceInfo getNamespaceByPrefix(String prefix);
+
+ /**
+ * Loads a namespace from persistent storage by specifying its uri.
+ *
+ * @param uri The uri of the namespace.
+ *
+ * @return The namespace, or null if no such namespace exists
+ */
+ NamespaceInfo getNamespaceByURI(String uri);
+
+ /**
+ * Loads all namespaces from persistent storage.
+ *
+ * @return A list of namespaces, possibilty empty
+ */
+ List getNamespaces();
+
+ //
+ // Workspaces
+ //
+ /**
+ * Adds a workspace to persistent storage.
+ */
+ WorkspaceInfo add(WorkspaceInfo workspace);
+
+ /**
+ * Removes a workspace from persistent storage.
+ */
+ void remove(WorkspaceInfo workspace);
+
+ /**
+ * Persists any modifications to a workspace to persistent storage.
+ *
+ * DAO implementations are responsible for triggering a {@link CatalogModifyEvent} by calling
+ * {@link Catalog#fireModified(CatalogInfo, List, List, List)}. This is the responsibility of
+ * the dao because it is best suited to knowing and tracking which attributes of the object have
+ * changed.
+ *
+ */
+ void save(WorkspaceInfo workspace);
+
+ /**
+ * Detaches a workspace from the underlying persistence layer.
+ *
+ * "Detaching" is specific to the underlying storage engine. But in general when an object
+ * is detached any proxies or uninitialized state of the object should be resolved.
+ *
+ *
+ * @see Catalog#detach(WorkspaceInfo)
+ */
+ WorkspaceInfo detach(WorkspaceInfo workspace);
+
+ /**
+ * Loads the default workspace from persistent storage.
+ *
+ * @return The workspace, or null if there is no default workspace set
+ */
+ WorkspaceInfo getDefaultWorkspace();
+
+ /**
+ * Sets the default workspace.
+ *
+ * DAO implementations are responsible for triggering a {@link CatalogModifyEvent} by calling
+ * {@link Catalog#fireModified(CatalogInfo, List, List, List)}. The source of the event is the
+ * catalog itself and changed property is "defaultWorkspace". The changed old/new values should
+ * the old/new workspaces respectively.
+ *
+ */
+ void setDefaultWorkspace(WorkspaceInfo workspace);
+
+ /**
+ * Loads a workspace from persistent storage by specifying its identifier.
+ *
+ * @param id The unique identifier of the workspace.
+ *
+ * @return THe workspace, or null if no such workspace exists.
+ */
+ WorkspaceInfo getWorkspace(String id);
+
+ /**
+ * Loads a workspace from persistent storage by specifying its name.
+ *
+ * @param name The name of the workspace.
+ *
+ * @return THe workspace, or null if no such workspace exists.
+ */
+ WorkspaceInfo getWorkspaceByName(String name);
+
+ /**
+ * Loads all workspaces from persistent storage.
+ *
+ * @return A list of workspaces, possibly empty.
+ */
+ List getWorkspaces();
+
+ //
+ // Styles
+ //
+ /**
+ * Adds a style to persistent storage.
+ */
+ StyleInfo add(StyleInfo style);
+
+ /**
+ * Removes a style from persistent storage.
+ */
+ void remove(StyleInfo style);
+
+ /**
+ * Persists any modifications to a style to persistent storage.
+ *
+ * DAO implementations are responsible for triggering a {@link CatalogModifyEvent} by calling
+ * {@link Catalog#fireModified(CatalogInfo, List, List, List)}. This is the responsibility of
+ * the dao because it is best suited to knowing and tracking which attributes of the object have
+ * changed.
+ *
+ */
+ void save(StyleInfo style);
+
+ /**
+ * Detaches a style from the underlying persistence layer.
+ *
+ * "Detaching" is specific to the underlying storage engine. But in general when an object
+ * is detached any proxies or uninitialized state of the object should be resolved.
+ *
+ *
+ * @see Catalog#detach(StyleInfo)
+ */
+ StyleInfo detach(StyleInfo style);
+
+ /**
+ * Loads a style from persistent storage by specifying its identifier.
+ *
+ * @param id The unique identifier of the style.
+ *
+ * @return The style, or null if no such style exists
+ */
+ StyleInfo getStyle(String id);
+
+ /**
+ * Loads a style from persistent storage by specifying its name.
+ *
+ * @param name The name of the style.
+ *
+ * @return The style, or null if no such style exists
+ */
+ StyleInfo getStyleByName(String name);
+
+ /**
+ * Loads all styles from persistent storage.
+ *
+ * @return A list of styles, possibly empty.
+ */
+ List getStyles();
+
+ /**
+ * Disposes the dao.
+ *
+ * Called from {@link Catalog#dispose()} and forces the dao to release any resources.
+ *
+ */
+ void dispose();
+
+ /**
+ * Called after the catalog has been initially started/loaded.
+ *
+ * This method gives the dao a chance to resolve any proxies or uninitialized state that are
+ * created during the loading process.
+ *
+ */
+ void resolve();
+
+ /**
+ * Pushes the data stored by this dao into another dao.
+ */
+ void syncTo(CatalogDAO other);
+}
diff --git a/main/src/main/java/org/geoserver/catalog/impl/CatalogImpl.java b/main/src/main/java/org/geoserver/catalog/impl/CatalogImpl.java
index 9accffc..604a51e 100644
--- a/main/src/main/java/org/geoserver/catalog/impl/CatalogImpl.java
+++ b/main/src/main/java/org/geoserver/catalog/impl/CatalogImpl.java
@@ -5,24 +5,22 @@
package org.geoserver.catalog.impl;
import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
import java.net.URI;
-import java.rmi.server.UID;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
-import org.apache.commons.collections.MultiHashMap;
import org.geoserver.catalog.Catalog;
+import org.geoserver.catalog.CatalogDAO;
import org.geoserver.catalog.CatalogException;
import org.geoserver.catalog.CatalogFactory;
import org.geoserver.catalog.CatalogInfo;
@@ -64,6 +62,10 @@ import org.opengis.feature.type.Name;
*
* @author Justin Deoliveira, The Open Planning Project
*
+ * TODO: remove synchronized blocks, make setting of default workspace/namespace part
+ * of dao contract
+ * TODO: move resolve() to dao
+ *
*/
public class CatalogImpl implements Catalog {
@@ -73,51 +75,11 @@ public class CatalogImpl implements Catalog {
private static final Logger LOGGER = Logging.getLogger(CatalogImpl.class);
/**
- * Contains the stores keyed by implementation class
+ * dao
*/
- protected MultiHashMap/* */stores = new MultiHashMap();
+ protected CatalogDAO dao;
/**
- * The default store keyed by workspace id
- */
- protected Map defaultStores = new HashMap();
-
- /**
- * resources
- */
- protected MultiHashMap/* */resources = new MultiHashMap();
-
- /**
- * namespaces
- */
- protected HashMap namespaces = new HashMap();
-
- /**
- * workspaces
- */
- protected HashMap workspaces = new HashMap();
-
- /**
- * layers
- */
- protected List layers = new ArrayList();
-
- /**
- * maps
- */
- protected List maps = new ArrayList();
-
- /**
- * layer groups
- */
- protected List layerGroups = new ArrayList();
-
- /**
- * styles
- */
- protected List styles = new ArrayList();
-
- /**
* listeners
*/
protected List listeners = new ArrayList();
@@ -129,9 +91,19 @@ public class CatalogImpl implements Catalog {
protected GeoServerResourceLoader resourceLoader;
public CatalogImpl() {
+ dao = new DefaultCatalogDAO(this);
resourcePool = new ResourcePool(this);
}
+ public CatalogDAO getDAO() {
+ return dao;
+ }
+
+ public void setDAO(CatalogDAO dao) {
+ this.dao = dao;
+ dao.setCatalog(this);
+ }
+
public String getId() {
return "catalog";
}
@@ -148,9 +120,11 @@ public class CatalogImpl implements Catalog {
}
validate(store, true);
- resolve(store);
- synchronized (stores) {
- stores.put(store.getClass(), store);
+
+ //TODO: remove synchronized block, need transactions
+ synchronized (dao) {
+ dao.add(resolve(store));
+
// if there is no default store use this one as the default
if(getDefaultDataStore(store.getWorkspace()) == null && store instanceof DataStoreInfo) {
setDefaultDataStore(store.getWorkspace(), (DataStoreInfo) store);
@@ -179,18 +153,19 @@ public class CatalogImpl implements Catalog {
if ( !getResourcesByStore(store, ResourceInfo.class).isEmpty() ) {
throw new IllegalArgumentException( "Unable to delete non-empty store.");
}
- store = unwrap(store);
- synchronized(stores) {
- stores.remove(store.getClass(),store);
+ //TODO: remove synchronized block, need transactions
+ synchronized(dao) {
+ dao.remove(store);
WorkspaceInfo workspace = store.getWorkspace();
DataStoreInfo defaultStore = getDefaultDataStore(workspace);
if (store.equals(defaultStore)) {
- defaultStores.remove(workspace.getId());
+ //TODO: this will fire multiple events, we want to fire only one
+ setDefaultDataStore(workspace, null);
// default removed, choose another store to become default if possible
- List dstores = getDataStoresByWorkspace(workspace);
+ List dstores = getStoresByWorkspace(workspace, DataStoreInfo.class);
if (!dstores.isEmpty()) {
setDefaultDataStore(workspace, (DataStoreInfo) dstores.get(0));
}
@@ -202,78 +177,52 @@ public class CatalogImpl implements Catalog {
public void save(StoreInfo store) {
validate(store, false);
-
- if ( store.getId() == null ) {
- //add it instead of saving
- add( store );
- return;
- }
-
+ dao.save(store);
saved(store);
}
- public T getStore(String id, Class clazz) {
- List l = lookup(clazz, stores);
- for (Iterator i = l.iterator(); i.hasNext();) {
- StoreInfo store = (StoreInfo) i.next();
- if (id.equals(store.getId())) {
- return ModificationProxy.create( (T) store, clazz );
- //return store;
- }
- }
+ public T detach(T store) {
+ return detached(store, dao.detach(store));
+ }
- return null;
+ public T getStore(String id, Class clazz) {
+ return dao.getStore(id, clazz);
}
public T getStoreByName(String name, Class clazz) {
- T store = getStoreByName( (WorkspaceInfo) null, name, clazz );
- if ( store != null ) {
- return store;
- }
-
- //look for secondary match
- List l = lookup(clazz, stores);
- ArrayList matches = new ArrayList();
- for (Iterator i = l.iterator(); i.hasNext();) {
- store = (T) i.next();
- if ( name.equals( store.getName() ) ) {
- matches.add( store );
- }
- }
-
- if ( matches.size() == 1 ) {
- return ModificationProxy.create( (T) matches.get( 0 ), clazz);
- }
-
- return null;
+ return getStoreByName((WorkspaceInfo) null, name, clazz);
}
public T getStoreByName(WorkspaceInfo workspace,
String name, Class clazz) {
- if ( workspace == null ) {
- workspace = getDefaultWorkspace();
+ WorkspaceInfo ws = workspace;
+ if (ws == null) {
+ ws = getDefaultWorkspace();
}
- if(name == null || name.equals(DEFAULT)) {
+ if(DataStoreInfo.class == clazz && (name == null || name.equals(Catalog.DEFAULT))) {
return (T) getDefaultDataStore(workspace);
}
- List l = lookup(clazz, stores);
- for (Iterator i = l.iterator(); i.hasNext();) {
- StoreInfo store = (StoreInfo) i.next();
- if (name.equals(store.getName()) && store.getWorkspace().equals( workspace )) {
- return ModificationProxy.create( (T) store, clazz );
- }
+ T store = dao.getStoreByName(ws, name, clazz);
+ if (store == null && workspace == null) {
+ store = dao.getStoreByName(DefaultCatalogDAO.ANY_WORKSPACE, name, clazz);
}
-
- return null;
+ return store;
}
public T getStoreByName(String workspaceName,
String name, Class clazz) {
- return getStoreByName(
- workspaceName != null ? getWorkspaceByName(workspaceName) : null, name, clazz);
+ if (workspaceName == null) {
+ return getStoreByName((WorkspaceInfo)null, name, clazz);
+ }
+
+ WorkspaceInfo workspace = getWorkspaceByName(workspaceName);
+ if (workspace != null) {
+ return getStoreByName(workspace, name, clazz);
+ }
+ return null;
}
public List getStoresByWorkspace(
@@ -294,25 +243,11 @@ public class CatalogImpl implements Catalog {
public List getStoresByWorkspace(
WorkspaceInfo workspace, Class clazz) {
- if ( workspace == null ) {
- workspace = getDefaultWorkspace();
- }
-
- List all = lookup(clazz, stores);
- List matches = new ArrayList();
-
- for (Iterator s = all.iterator(); s.hasNext();) {
- StoreInfo store = (StoreInfo) s.next();
- if (workspace.equals(store.getWorkspace())) {
- matches.add(store);
- }
- }
-
- return ModificationProxy.createList(matches,clazz);
+ return dao.getStoresByWorkspace(workspace, clazz);
}
public List getStores(Class clazz) {
- return ModificationProxy.createList(lookup(clazz, stores) , clazz);
+ return dao.getStores(clazz);
}
public DataStoreInfo getDataStore(String id) {
@@ -344,32 +279,23 @@ public class CatalogImpl implements Catalog {
}
public DataStoreInfo getDefaultDataStore(WorkspaceInfo workspace) {
- if(defaultStores.containsKey(workspace.getId())) {
- DataStoreInfo defaultStore = defaultStores.get(workspace.getId());
- return ModificationProxy.create(defaultStore, DataStoreInfo.class);
- } else {
- return null;
- }
+ return dao.getDefaultDataStore(workspace);
}
public void setDefaultDataStore(WorkspaceInfo workspace, DataStoreInfo store) {
- // basic sanity check
- if (store.getWorkspace() == null) {
- throw new IllegalArgumentException("The store has not been assigned a workspace");
- }
-
- if (!store.getWorkspace().equals(workspace)) {
- throw new IllegalArgumentException("Trying to mark as default " + "for workspace "
- + workspace.getName() + " a store that " + "is contained in "
- + store.getWorkspace().getName());
+ if (store != null) {
+ // basic sanity check
+ if (store.getWorkspace() == null) {
+ throw new IllegalArgumentException("The store has not been assigned a workspace");
+ }
+
+ if (!store.getWorkspace().equals(workspace)) {
+ throw new IllegalArgumentException("Trying to mark as default " + "for workspace "
+ + workspace.getName() + " a store that " + "is contained in "
+ + store.getWorkspace().getName());
+ }
}
-
- DataStoreInfo old = defaultStores.get(workspace.getId());
- defaultStores.put(workspace.getId(), store);
-
- //fire change event
- fireModified(this,
- Arrays.asList("defaultDataStore"), Arrays.asList(old), Arrays.asList(store));
+ dao.setDefaultDataStore(workspace, store);
}
public CoverageStoreInfo getCoverageStore(String id) {
@@ -410,10 +336,12 @@ public class CatalogImpl implements Catalog {
//default to default namespace
resource.setNamespace( getDefaultNamespace() );
}
-
+ if ( resource.getNativeName() == null ) {
+ resource.setNativeName(resource.getName());
+ }
validate(resource,true);
- resolve(resource);
- resources.put(resource.getClass(), resource);
+
+ dao.add(resolve(resource));
added(resource);
}
@@ -421,6 +349,9 @@ public class CatalogImpl implements Catalog {
if ( isNull(resource.getName()) ) {
throw new NullPointerException( "Resource name must not be null");
}
+ if ( isNull(resource.getNativeName())) {
+ throw new NullPointerException( "Resource native name must not be null");
+ }
if ( resource.getStore() == null ) {
throw new IllegalArgumentException( "Resource must be part of a store");
}
@@ -449,80 +380,58 @@ public class CatalogImpl implements Catalog {
if ( !getLayers( resource ).isEmpty() ) {
throw new IllegalArgumentException( "Unable to delete resource referenced by layer");
}
- resource = unwrap(resource);
- resources.remove(resource.getClass(), resource);
+ dao.remove(resource);
removed(resource);
}
public void save(ResourceInfo resource) {
validate(resource,false);
+ dao.save(resource);
saved(resource);
}
+ public T detach(T resource) {
+ return detached(resource, dao.detach(resource));
+ }
+
public T getResource(String id, Class clazz) {
- List l = lookup(clazz, resources);
- for (Iterator i = l.iterator(); i.hasNext();) {
- ResourceInfo resource = (ResourceInfo) i.next();
- if (id.equals(resource.getId())) {
- return ModificationProxy.create((T) resource, clazz );
- }
- }
-
- return null;
+ return dao.getResource(id, clazz);
}
public T getResourceByName(String ns, String name, Class clazz) {
-
- NamespaceInfo namespace = null;
if ("".equals( ns ) ) {
- ns = null;
- }
- if ( ns == null ) {
- //if namespace was null, try the default namespace
- if ( getDefaultNamespace() != null ) {
- namespace = getDefaultNamespace();
- }
- }
- else {
- namespace = getNamespaceByPrefix( ns );
- if ( namespace == null ) {
- namespace = getNamespaceByURI( ns );
- }
+ ns = null;
}
- List l = lookup(clazz, resources);
- if ( namespace != null ) {
- for (Iterator i = l.iterator(); i.hasNext();) {
- ResourceInfo resource = (ResourceInfo) i.next();
- if (name.equals(resource.getName())) {
- NamespaceInfo namespace1 = resource.getNamespace();
- if (namespace1 != null && namespace1.equals( namespace )) {
- return ModificationProxy.create( (T) resource, clazz );
- }
- }
- }
- }
-
- if ( ns == null ) {
- // no namespace was specified, so do an exhaustive lookup
- List matches = new ArrayList();
- for (Iterator i = l.iterator(); i.hasNext();) {
- ResourceInfo resource = (ResourceInfo) i.next();
- if (name.equals(resource.getName())) {
- matches.add( resource );
- }
+ if (ns != null) {
+ NamespaceInfo namespace = getNamespaceByPrefix(ns);
+ if (namespace == null) {
+ namespace = getNamespaceByURI(ns);
}
- if ( matches.size() == 1 ) {
- return ModificationProxy.create( (T) matches.get( 0 ), clazz );
+ if (namespace != null) {
+ return getResourceByName(namespace, name, clazz);
}
+
+ return null;
}
- return null;
+
+ return getResourceByName((NamespaceInfo) null, name, clazz);
+
}
public T getResourceByName(NamespaceInfo ns,
String name, Class clazz) {
- return getResourceByName( ns != null ? ns.getPrefix() : null , name, clazz);
+
+ NamespaceInfo namespace = ns;
+ if (namespace == null) {
+ namespace = getDefaultNamespace();
+ }
+ T resource = dao.getResourceByName(namespace, name, clazz);
+ if (resource == null && ns == null) {
+ resource = dao.getResourceByName(DefaultCatalogDAO.ANY_NAMESPACE, name, clazz);
+ }
+ return resource;
}
public T getResourceByName(Name name, Class clazz) {
@@ -545,30 +454,11 @@ public class CatalogImpl implements Catalog {
}
public List getResources(Class clazz) {
- return ModificationProxy.createList( lookup(clazz,resources), clazz );
+ return dao.getResources(clazz);
}
public List getResourcesByNamespace(NamespaceInfo namespace, Class clazz) {
- List all = lookup(clazz, resources);
- List matches = new ArrayList();
-
- if ( namespace == null ) {
- namespace = getDefaultNamespace();
- }
-
- for (Iterator r = all.iterator(); r.hasNext();) {
- ResourceInfo resource = (ResourceInfo) r.next();
- if (namespace != null ) {
- if (namespace.equals(resource.getNamespace())) {
- matches.add( resource );
- }
- }
- else if ( resource.getNamespace() == null ) {
- matches.add(resource);
- }
- }
-
- return ModificationProxy.createList( matches, clazz );
+ return dao.getResourcesByNamespace(namespace, clazz);
}
public List getResourcesByNamespace(
@@ -590,31 +480,12 @@ public class CatalogImpl implements Catalog {
public T getResourceByStore(StoreInfo store,
String name, Class clazz) {
- List all = lookup(clazz,resources);
- for (Iterator r = all.iterator(); r.hasNext(); ) {
- ResourceInfo resource = (ResourceInfo) r.next();
- if ( name.equals( resource.getName() ) && store.equals( resource.getStore() ) ) {
- return ModificationProxy.create((T)resource, clazz);
- }
-
- }
-
- return null;
+ return dao.getResourceByStore(store, name, clazz);
}
public List getResourcesByStore(
StoreInfo store, Class clazz) {
- List all = lookup(clazz,resources);
- List matches = new ArrayList();
-
- for (Iterator r = all.iterator(); r.hasNext();) {
- ResourceInfo resource = (ResourceInfo) r.next();
- if (store.equals(resource.getStore())) {
- matches.add(resource);
- }
- }
-
- return ModificationProxy.createList( matches, clazz );
+ return dao.getResourcesByStore(store, clazz);
}
public FeatureTypeInfo getFeatureType(String id) {
@@ -708,7 +579,6 @@ public class CatalogImpl implements Catalog {
// Layer methods
public void add(LayerInfo layer) {
validate(layer,true);
- resolve(layer);
if ( layer.getType() == null ) {
if ( layer.getResource() instanceof FeatureTypeInfo ) {
@@ -723,7 +593,7 @@ public class CatalogImpl implements Catalog {
}
}
- layers.add(layer);
+ dao.add(resolve(layer));
added(layer);
}
@@ -754,30 +624,28 @@ public class CatalogImpl implements Catalog {
public void remove(LayerInfo layer) {
//ensure no references to the layer
- for ( LayerGroupInfo lg : layerGroups ) {
+ for ( LayerGroupInfo lg : dao.getLayerGroups() ) {
if ( lg.getLayers().contains( layer ) ) {
String msg = "Unable to delete layer referenced by layer group '"+lg.getName()+"'";
throw new IllegalArgumentException( msg );
}
}
- layers.remove(unwrap(layer));
+ dao.remove(layer);
removed(layer);
}
public void save(LayerInfo layer) {
validate( layer, false );
+ dao.save(layer);
saved(layer);
}
+
+ public LayerInfo detach(LayerInfo layer) {
+ return detached(layer, dao.detach(layer));
+ }
public LayerInfo getLayer(String id) {
- for (Iterator l = layers.iterator(); l.hasNext();) {
- LayerInfo layer = (LayerInfo) l.next();
- if (id.equals(layer.getId())) {
- return ModificationProxy.create( layer, LayerInfo.class );
- }
- }
-
- return null;
+ return dao.getLayer(id);
}
@@ -802,79 +670,45 @@ public class CatalogImpl implements Catalog {
prefix = name.substring( 0, colon );
resource = name.substring( colon + 1 );
- for (Iterator l = layers.iterator(); l.hasNext();) {
- LayerInfo layer = (LayerInfo) l.next();
- ResourceInfo r = layer.getResource();
-
- if ( prefix.equals( r.getNamespace().getPrefix() ) && resource.equals( r.getName() ) ) {
- return ModificationProxy.create( layer, LayerInfo.class );
+ ResourceInfo r = getResourceByName(prefix, resource, ResourceInfo.class);
+ if (r != null) {
+ List layers = getLayers(r);
+ if (layers.size() == 1) {
+ return layers.get(0);
}
+
}
+ return null;
}
else {
- //search by layer name
- for (Iterator l = layers.iterator(); l.hasNext();) {
- LayerInfo layer = (LayerInfo) l.next();
- if ( name.equals( layer.getName() ) ) {
- return ModificationProxy.create( layer, LayerInfo.class );
- }
- }
+ return dao.getLayerByName(name);
}
- return null;
}
public List getLayers(ResourceInfo resource) {
- List matches = new ArrayList();
- for (Iterator l = layers.iterator(); l.hasNext();) {
- LayerInfo layer = (LayerInfo) l.next();
- if ( resource.equals( layer.getResource() ) ) {
- matches.add( layer );
- }
- }
-
- return ModificationProxy.createList(matches,LayerInfo.class);
+ return dao.getLayers(resource);
}
public List getLayers(StyleInfo style) {
- List matches = new ArrayList();
- for (Iterator l = layers.iterator(); l.hasNext();) {
- LayerInfo layer = (LayerInfo) l.next();
- if ( style.equals( layer.getDefaultStyle() ) || layer.getStyles().contains( style ) ) {
- matches.add( layer );
- }
- }
-
- return ModificationProxy.createList(matches,LayerInfo.class);
+ return dao.getLayers(style);
}
public List getLayers() {
- return ModificationProxy.createList( new ArrayList(layers), LayerInfo.class );
+ return dao.getLayers();
}
// Map methods
public MapInfo getMap(String id) {
- for (MapInfo map : maps) {
- if (id.equals(map.getId())) {
- return ModificationProxy.create(map,MapInfo.class);
- }
- }
-
- return null;
+ return dao.getMap(id);
}
public MapInfo getMapByName(String name) {
- for (MapInfo map : maps) {
- if (name.equals(map.getName())) {
- return ModificationProxy.create(map,MapInfo.class);
- }
- }
-
- return null;
+ return dao.getMapByName(name);
}
public List getMaps() {
- return ModificationProxy.createList( new ArrayList(maps), MapInfo.class );
+ return dao.getMaps();
}
public void add(LayerGroupInfo layerGroup) {
@@ -885,10 +719,10 @@ public class CatalogImpl implements Catalog {
for ( LayerInfo l : layerGroup.getLayers() ) {
// default style
layerGroup.getStyles().add(null);
- }
+ }
}
- layerGroups.add( layerGroup );
+ layerGroup = dao.add(layerGroup);
added( layerGroup );
}
@@ -913,97 +747,80 @@ public class CatalogImpl implements Catalog {
}
public void remove(LayerGroupInfo layerGroup) {
- layerGroups.remove( unwrap(layerGroup) );
+ dao.remove(layerGroup);
removed( layerGroup );
}
public void save(LayerGroupInfo layerGroup) {
validate(layerGroup,false);
+ dao.save(layerGroup);
saved(layerGroup);
}
+ public LayerGroupInfo detach(LayerGroupInfo layerGroup) {
+ return detached(layerGroup, dao.detach(layerGroup));
+ }
+
public List getLayerGroups() {
- return ModificationProxy.createList( new ArrayList(layerGroups), LayerGroupInfo.class );
+ return dao.getLayerGroups();
}
public LayerGroupInfo getLayerGroup(String id) {
- for (LayerGroupInfo layerGroup : layerGroups ) {
- if ( id.equals( layerGroup.getId() ) ) {
- return ModificationProxy.create(layerGroup,LayerGroupInfo.class);
- }
- }
-
- return null;
+ return dao.getLayerGroup(id);
}
public LayerGroupInfo getLayerGroupByName(String name) {
- for (LayerGroupInfo layerGroup : layerGroups ) {
- if ( name.equals( layerGroup.getName() ) ) {
- return ModificationProxy.create(layerGroup,LayerGroupInfo.class);
- }
- }
-
- return null;
+ return dao.getLayerGroupByName(name);
}
public void add(MapInfo map) {
- resolve(map);
- maps.add(map);
+ dao.add(resolve(map));
added(map);
}
public void remove(MapInfo map) {
- maps.remove(unwrap(map));
+ dao.remove(map);
removed(map);
}
public void save(MapInfo map) {
- saved( map );
+ dao.save(map);
+ saved(map);
+ }
+
+ public MapInfo detach(MapInfo map) {
+ return detached(map, dao.detach(map));
}
// Namespace methods
public NamespaceInfo getNamespace(String id) {
- for (NamespaceInfo namespace : namespaces.values() ) {
- if (id.equals(namespace.getId())) {
- return ModificationProxy.create( namespace, NamespaceInfo.class );
- }
- }
-
- return null;
+ return dao.getNamespace(id);
}
public NamespaceInfo getNamespaceByPrefix(String prefix) {
- NamespaceInfo ns = namespaces.get( prefix );
- return ns != null ? ModificationProxy.create(ns, NamespaceInfo.class ) : null;
- }
-
- public NamespaceInfo getNamespaceByURI(String uri) {
- for (NamespaceInfo namespace : namespaces.values() ) {
- if (uri.equals(namespace.getURI())) {
- return ModificationProxy.create( namespace, NamespaceInfo.class );
+ if (prefix == null || Catalog.DEFAULT.equals(prefix)) {
+ NamespaceInfo ns = getDefaultNamespace();
+ if (ns != null) {
+ prefix = ns.getPrefix();
}
}
+
+ return dao.getNamespaceByPrefix(prefix);
+ }
- return null;
+ public NamespaceInfo getNamespaceByURI(String uri) {
+ return dao.getNamespaceByURI(uri);
}
public List getNamespaces() {
- ArrayList ns = new ArrayList();
- for ( Map.Entry e : namespaces.entrySet() ) {
- if ( e.getKey() == null || e.getKey().equals(DEFAULT))
- continue;
- ns.add( e.getValue() );
- }
-
- return ModificationProxy.createList( ns, NamespaceInfo.class );
+ return dao.getNamespaces();
}
public void add(NamespaceInfo namespace) {
validate(namespace,true);
- resolve(namespace);
- synchronized (namespaces) {
- namespaces.put(namespace.getPrefix(),namespace);
+ synchronized (dao) {
+ dao.add(resolve(namespace));
if ( getDefaultNamespace() == null ) {
setDefaultNamespace(namespace);
}
@@ -1048,67 +865,45 @@ public class CatalogImpl implements Catalog {
throw new IllegalArgumentException( "Unable to delete non-empty namespace.");
}
- NamespaceInfo defaultNamespace = getDefaultNamespace();
- if (namespace.equals(defaultNamespace)) {
- namespaces.remove(null);
- namespaces.remove(DEFAULT);
- }
-
- namespaces.remove(namespace.getPrefix());
+ dao.remove(namespace);
removed(namespace);
}
public void save(NamespaceInfo namespace) {
validate(namespace,false);
- ModificationProxy h =
- (ModificationProxy) Proxy.getInvocationHandler(namespace);
-
- NamespaceInfo ns = (NamespaceInfo) h.getProxyObject();
- if ( !namespace.getPrefix().equals( ns.getPrefix() ) ) {
- synchronized (namespaces) {
- namespaces.remove( ns.getPrefix() );
- namespaces.put( namespace.getPrefix(), ns );
- }
- }
-
+ dao.save(namespace);
saved(namespace);
}
+
+ public NamespaceInfo detach(NamespaceInfo namespace) {
+ return detached(namespace, dao.detach(namespace));
+ }
public NamespaceInfo getDefaultNamespace() {
- return namespaces.containsKey(null) ?
- ModificationProxy.create(namespaces.get( null ),NamespaceInfo.class) : null;
+ return dao.getDefaultNamespace();
}
public void setDefaultNamespace(NamespaceInfo defaultNamespace) {
- NamespaceInfo ns = namespaces.get( defaultNamespace.getPrefix() );
+ NamespaceInfo ns = getNamespaceByPrefix( defaultNamespace.getPrefix() );
if ( ns == null ) {
throw new IllegalArgumentException( "No such namespace: '" + defaultNamespace.getPrefix() + "'" );
}
-
- NamespaceInfo old = namespaces.get(null);
- namespaces.put( null, ns );
- namespaces.put( DEFAULT, ns );
-
- //fire change event
- fireModified(this,
- Arrays.asList("defaultNamespace"), Arrays.asList(old), Arrays.asList(defaultNamespace));
-
+ dao.setDefaultNamespace(defaultNamespace);
}
// Workspace methods
public void add(WorkspaceInfo workspace) {
validate(workspace,true);
- if ( workspaces.containsKey( workspace.getName() ) ) {
+ if ( getWorkspaceByName(workspace.getName()) != null ) {
throw new IllegalArgumentException( "Workspace with name '" + workspace.getName() + "' already exists.");
}
- resolve(workspace);
- synchronized (workspaces) {
- workspaces.put( workspace.getName(), workspace );
+ synchronized (dao) {
+ dao.add(resolve(workspace));
// if there is no default workspace use this one as the default
- if ( workspaces.get( null ) == null ) {
+ if ( getDefaultWorkspace() == null ) {
setDefaultWorkspace(workspace);
}
}
@@ -1141,117 +936,83 @@ public class CatalogImpl implements Catalog {
if ( !getStoresByWorkspace( workspace, StoreInfo.class).isEmpty() ) {
throw new IllegalArgumentException( "Cannot delete non-empty workspace.");
}
-
- workspaces.remove( workspace.getName() );
-
- WorkspaceInfo defaultWorkspace = getDefaultWorkspace();
- if (workspace.equals(defaultWorkspace)) {
- workspaces.remove(null);
- workspaces.remove(DEFAULT);
-
- //default removed, choose another workspace to become default
- if (!workspaces.isEmpty()) {
- setDefaultWorkspace(workspaces.values().iterator().next());
+
+ //TODO: remove synchronized block, need transactions
+ synchronized(dao) {
+ dao.remove(workspace);
+
+ WorkspaceInfo defaultWorkspace = getDefaultWorkspace();
+ if (workspace.equals(defaultWorkspace) || defaultWorkspace == null) {
+ List workspaces = dao.getWorkspaces();
+
+ defaultWorkspace = null;
+ if (!workspaces.isEmpty()) {
+ defaultWorkspace = workspaces.get(0);
+ }
+
+ setDefaultWorkspace(defaultWorkspace);
}
}
-
-
+
removed( workspace );
}
public void save(WorkspaceInfo workspace) {
validate(workspace,false);
- ModificationProxy h =
- (ModificationProxy) Proxy.getInvocationHandler(workspace);
-
- WorkspaceInfo ws = (WorkspaceInfo) h.getProxyObject();
- if ( !workspace.getName().equals( ws.getName() ) ) {
- synchronized (workspaces) {
- workspaces.remove( ws.getName() );
- workspaces.put( workspace.getName(), ws );
- }
- }
-
+ dao.save(workspace);
saved(workspace);
}
+ public WorkspaceInfo detach(WorkspaceInfo workspace) {
+ return detached(workspace, dao.detach(workspace));
+ }
+
public WorkspaceInfo getDefaultWorkspace() {
- return workspaces.containsKey( null ) ?
- ModificationProxy.create( workspaces.get( null ), WorkspaceInfo.class ) : null;
+ return dao.getDefaultWorkspace();
}
public void setDefaultWorkspace(WorkspaceInfo workspace) {
- WorkspaceInfo old = workspaces.get(null);
- workspaces.put( null, workspace );
- workspaces.put( "default", workspace );
-
- //fire change event
- fireModified(this,
- Arrays.asList("defaultWorkspace"), Arrays.asList(old), Arrays.asList(workspace));
+ if (workspace != null && dao.getWorkspaceByName(workspace.getName()) == null) {
+ dao.add(workspace);
+ }
+ dao.setDefaultWorkspace(workspace);
}
public List getWorkspaces() {
- ArrayList ws = new ArrayList();
-
- //strip out default namespace
- for ( Map.Entry e : workspaces.entrySet() ) {
- if ( e.getKey() == null || e.getKey().equals(DEFAULT) ) {
- continue;
- }
-
- ws.add( e.getValue() );
- }
-
- return ModificationProxy.createList( ws, WorkspaceInfo.class );
+ return dao.getWorkspaces();
}
public WorkspaceInfo getWorkspace(String id) {
- for ( WorkspaceInfo ws : workspaces.values() ) {
- if ( id.equals( ws.getId() ) ) {
- return ModificationProxy.create(ws,WorkspaceInfo.class);
- }
- }
-
- return null;
+ return dao.getWorkspace(id);
}
public WorkspaceInfo getWorkspaceByName(String name) {
- return workspaces.containsKey(name) ?
- ModificationProxy.create( workspaces.get( name ), WorkspaceInfo.class ) : null;
+ if (name == null || Catalog.DEFAULT.equals(name)) {
+ WorkspaceInfo ws = getDefaultWorkspace();
+ if (ws != null) {
+ name = ws.getName();
+ }
+ }
+ return dao.getWorkspaceByName(name);
}
// Style methods
public StyleInfo getStyle(String id) {
- for (Iterator s = styles.iterator(); s.hasNext();) {
- StyleInfo style = (StyleInfo) s.next();
- if (id.equals(style.getId())) {
- return ModificationProxy.create(style,StyleInfo.class);
- }
- }
-
- return null;
+ return dao.getStyle(id);
}
public StyleInfo getStyleByName(String name) {
- for (Iterator s = styles.iterator(); s.hasNext();) {
- StyleInfo style = (StyleInfo) s.next();
- if (name.equals(style.getName())) {
- return ModificationProxy.create(style,StyleInfo.class);
- }
- }
-
- return null;
+ return dao.getStyleByName(name);
}
public List getStyles() {
- return ModificationProxy.createList(styles,StyleInfo.class);
+ return dao.getStyles();
}
public void add(StyleInfo style) {
validate(style,true);
- resolve(style);
- styles.add(style);
+ dao.add(resolve(style));
added(style);
}
@@ -1271,18 +1032,24 @@ public class CatalogImpl implements Catalog {
public void remove(StyleInfo style) {
//ensure no references to the style
- for ( LayerInfo l : layers ) {
+ for ( LayerInfo l : dao.getLayers() ) {
if ( style.equals( l.getDefaultStyle() ) || l.getStyles().contains( style )) {
throw new IllegalArgumentException( "Unable to delete style referenced by '"+ l.getName()+"'");
}
}
- styles.remove(unwrap(style));
+
+ dao.remove(style);
removed(style);
}
public void save(StyleInfo style) {
validate(style,false);
- saved( style );
+ dao.save(style);
+ saved(style);
+ }
+
+ public StyleInfo detach(StyleInfo style) {
+ return detached(style, dao.detach(style));
}
// Event methods
@@ -1319,70 +1086,27 @@ public class CatalogImpl implements Catalog {
this.resourceLoader = resourceLoader;
}
public void dispose() {
- if ( stores != null ) stores.clear();
- if ( defaultStores != null ) defaultStores.clear();
- if ( resources != null ) resources.clear();
- if ( namespaces != null ) namespaces.clear();
- if ( workspaces != null ) workspaces.clear();
- if ( layers != null ) layers.clear();
- if ( layerGroups != null ) layerGroups.clear();
- if ( maps != null ) maps.clear();
- if ( styles != null ) styles.clear();
+ dao.dispose();
if ( listeners != null ) listeners.clear();
-
if ( resourcePool != null ) resourcePool.dispose();
}
- List lookup(Class clazz, MultiHashMap map) {
- ArrayList result = new ArrayList();
- for (Iterator k = map.keySet().iterator(); k.hasNext();) {
- Class key = (Class) k.next();
- if (clazz.isAssignableFrom(key)) {
- result.addAll(map.getCollection(key));
- }
- }
-
- return result;
- }
-
protected void added(CatalogInfo object) {
fireAdded( object );
}
- protected void fireAdded(CatalogInfo object) {
+ protected void removed(CatalogInfo object) {
+ fireRemoved( object );
+ }
+
+ public void fireAdded(CatalogInfo object) {
CatalogAddEventImpl event = new CatalogAddEventImpl();
event.setSource(object);
event(event);
}
-
- protected void saved(CatalogInfo object) {
- //this object is a proxy
- ModificationProxy h =
- (ModificationProxy) Proxy.getInvocationHandler(object);
-
- //get the real object
- CatalogInfo real = (CatalogInfo) h.getProxyObject();
-
- //fire out what changed
- List propertyNames = h.getPropertyNames();
- List newValues = h.getNewValues();
- List oldValues = h.getOldValues();
-
- //TODO: protect this original object, perhaps with another proxy
- fireModified( real, propertyNames, oldValues, newValues );
-
- //commit to the original object
- h.commit();
-
- //resolve to do a sync on the object
- //syncIdWithName(real);
-
- //fire the post modify event
- firePostModified( real );
- }
- protected void fireModified(CatalogInfo object, List propertyNames, List oldValues,
+ public void fireModified(CatalogInfo object, List propertyNames, List oldValues,
List newValues) {
CatalogModifyEventImpl event = new CatalogModifyEventImpl();
@@ -1394,13 +1118,14 @@ public class CatalogImpl implements Catalog {
event(event);
}
- protected void firePostModified(CatalogInfo object) {
+ public void firePostModified(CatalogInfo object) {
CatalogPostModifyEventImpl event = new CatalogPostModifyEventImpl();
event.setSource( object);
event(event);
}
- protected void removed(CatalogInfo object) {
+
+ public void fireRemoved(CatalogInfo object) {
CatalogRemoveEventImpl event = new CatalogRemoveEventImpl();
event.setSource(object);
@@ -1437,76 +1162,20 @@ public class CatalogImpl implements Catalog {
}
}
+ protected void saved(CatalogInfo info) {
+ firePostModified(info);
+ }
+
+ public static Object unwrap(Object obj) {
+ return obj;
+ }
+
/**
* Implementation method for resolving all {@link ResolvingProxy} instances.
*/
public void resolve() {
- //JD creation checks are done here b/c when xstream depersists
- // some members may be left null
-
- //workspaces
- if ( workspaces == null ) {
- workspaces = new HashMap();
- }
- for ( WorkspaceInfo ws : workspaces.values() ) {
- resolve(ws);
- }
-
- //namespaces
- if ( namespaces == null ) {
- namespaces = new HashMap();
- }
- for ( NamespaceInfo ns : namespaces.values() ) {
- resolve(ns);
- }
-
- //stores
- if ( stores == null ) {
- stores = new MultiHashMap();
- }
- for ( Object o : stores.values() ) {
- resolve((StoreInfoImpl)o);
- }
-
- //styles
- if ( styles == null ) {
- styles = new ArrayList();
- }
- for ( StyleInfo s : styles ) {
- resolve(s);
- }
-
- //resources
- if ( resources == null ) {
- resources = new MultiHashMap();
- }
- for( Object o : resources.values() ) {
- resolve((ResourceInfo)o);
- }
-
- //layers
- if ( layers == null ) {
- layers = new ArrayList();
- }
- for ( LayerInfo l : layers ) {
- resolve(l);
- }
-
- //layer groups
- if ( layerGroups == null ) {
- layerGroups = new ArrayList();
- }
- for ( LayerGroupInfo lg : layerGroups ) {
- resolve(lg);
- }
-
- //maps
- if ( maps == null ) {
- maps = new ArrayList();
- }
- for ( MapInfo m : maps ) {
- resolve(m);
- }
+ dao.setCatalog(this);
+ dao.resolve();
if ( listeners == null ) {
listeners = new ArrayList();
@@ -1517,42 +1186,29 @@ public class CatalogImpl implements Catalog {
}
}
- protected void resolve(WorkspaceInfo workspace) {
- setId(workspace);
+ protected WorkspaceInfo resolve(WorkspaceInfo workspace) {
resolveCollections(workspace);
+ return workspace;
}
- protected void resolve(NamespaceInfo namespace) {
- setId(namespace);
+ protected NamespaceInfo resolve(NamespaceInfo namespace) {
resolveCollections(namespace);
+ return namespace;
}
- protected void resolve(StoreInfo store) {
- setId(store);
- StoreInfoImpl s = (StoreInfoImpl) store;
-
- //resolve the workspace
- WorkspaceInfo resolved = ResolvingProxy.resolve( this, s.getWorkspace());
- if ( resolved != null ) {
- s.setWorkspace( resolved );
- }
- else {
- //this means the workspace has not yet been added to the catalog, keep the proxy around
- }
- resolveCollections(s);
+ protected StoreInfo resolve(StoreInfo store) {
+ resolveCollections(store);
+ StoreInfoImpl s = (StoreInfoImpl) store;
s.setCatalog( this );
+
+ return store;
}
- protected void resolve(ResourceInfo resource) {
- setId(resource);
- ResourceInfoImpl r = (ResourceInfoImpl) resource;
+ protected ResourceInfo resolve(ResourceInfo resource) {
- //resolve the store
- StoreInfo resolved = ResolvingProxy.resolve( this, r.getStore() );
- if ( resolved != null ) {
- r.setStore( resolved );
- }
+ ResourceInfoImpl r = (ResourceInfoImpl) resource;
+ r.setCatalog(this);
if ( resource instanceof FeatureTypeInfo ) {
resolve( (FeatureTypeInfo) resource );
@@ -1563,20 +1219,21 @@ public class CatalogImpl implements Catalog {
if(r instanceof WMSLayerInfo){
resolve((WMSLayerInfo) resource);
}
- r.setCatalog(this);
+
+ return resource;
}
- private void resolve(CoverageInfo r) {
+ private CoverageInfo resolve(CoverageInfo r) {
CoverageInfoImpl c = (CoverageInfoImpl)r;
- if(c.getDimensions() == null) {
- c.setDimensions(new ArrayList());
- } else {
+ if(c.getDimensions() != null) {
for (CoverageDimensionInfo dim : c.getDimensions()) {
- if(dim.getNullValues() == null)
+ if(dim.getNullValues() == null) {
((CoverageDimensionImpl) dim).setNullValues(new ArrayList());
+ }
}
}
resolveCollections(r);
+ return r;
}
/**
@@ -1584,52 +1241,39 @@ public class CatalogImpl implements Catalog {
* going trough {@link #resolve(ResourceInfo)}
* @param featureType
*/
- private void resolve(FeatureTypeInfo featureType) {
+ private FeatureTypeInfo resolve(FeatureTypeInfo featureType) {
FeatureTypeInfoImpl ft = (FeatureTypeInfoImpl) featureType;
resolveCollections(ft);
+ return ft;
}
- private void resolve(WMSLayerInfo wmsLayer) {
+ private WMSLayerInfo resolve(WMSLayerInfo wmsLayer) {
WMSLayerInfoImpl impl = (WMSLayerInfoImpl) wmsLayer;
resolveCollections(impl);
+ return wmsLayer;
}
- protected void resolve(LayerInfo layer) {
- setId(layer);
+ protected LayerInfo resolve(LayerInfo layer) {
if (layer.getAttribution() == null) {
layer.setAttribution(getFactory().createAttribution());
}
resolveCollections(layer);
+ return layer;
}
- protected void resolve(LayerGroupInfo layerGroup) {
- setId(layerGroup);
+ protected LayerGroupInfo resolve(LayerGroupInfo layerGroup) {
resolveCollections(layerGroup);
- LayerGroupInfoImpl lg = (LayerGroupInfoImpl) layerGroup;
-
- for ( int i = 0; i < lg.getLayers().size(); i++ ) {
- LayerInfo l = lg.getLayers().get( i );
- LayerInfo resolved = ResolvingProxy.resolve( this, l );
- lg.getLayers().set( i, resolved );
- }
-
- for ( int i = 0; i < lg.getStyles().size(); i++ ) {
- StyleInfo s = lg.getStyles().get( i );
- if(s != null) {
- StyleInfo resolved = ResolvingProxy.resolve( this, s );
- lg.getStyles().set( i, resolved );
- }
- }
-
+ return layerGroup;
}
- protected void resolve(StyleInfo style) {
- setId(style);
+ protected StyleInfo resolve(StyleInfo style) {
((StyleInfoImpl)style).setCatalog( this );
+ return style;
}
- protected void resolve(MapInfo map) {
- setId(map);
+ protected MapInfo resolve(MapInfo map) {
+ resolveCollections(map);
+ return map;
}
/**
@@ -1687,27 +1331,16 @@ public class CatalogImpl implements Catalog {
}
}
- protected void setId( Object o ) {
- if ( OwsUtils.get( o, "id") == null ) {
- String uid = new UID().toString();
- OwsUtils.set( o, "id", o.getClass().getSimpleName() + "-"+uid );
- }
- }
-
protected boolean isNull( String string ) {
return string == null || "".equals( string.trim() );
}
+ T detached(T original, T detached) {
+ return detached != null ? detached : original;
+ }
+
public void sync( CatalogImpl other ) {
- stores = other.stores;
- defaultStores = other.defaultStores;
- resources = other.resources;
- namespaces = other.namespaces;
- workspaces = other.workspaces;
- layers = other.layers;
- maps = other.maps;
- layerGroups = other.layerGroups;
- styles = other.styles;
+ other.dao.syncTo(dao);
listeners = other.listeners;
if ( resourcePool != other.resourcePool ) {
@@ -1718,10 +1351,6 @@ public class CatalogImpl implements Catalog {
resourceLoader = other.resourceLoader;
}
- public static T unwrap(T obj) {
- return ModificationProxy.unwrap(obj);
- }
-
public void accept(CatalogVisitor visitor) {
visitor.visit(this);
}
diff --git a/main/src/main/java/org/geoserver/catalog/impl/CoverageDimensionImpl.java b/main/src/main/java/org/geoserver/catalog/impl/CoverageDimensionImpl.java
index 0fceffe..5021698 100644
--- a/main/src/main/java/org/geoserver/catalog/impl/CoverageDimensionImpl.java
+++ b/main/src/main/java/org/geoserver/catalog/impl/CoverageDimensionImpl.java
@@ -73,4 +73,55 @@ public class CoverageDimensionImpl implements CoverageDimensionInfo {
public void setNullValues(List nullValues) {
this.nullValues = nullValues;
}
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((description == null) ? 0 : description.hashCode());
+ result = prime * result + ((id == null) ? 0 : id.hashCode());
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ result = prime * result + ((nullValues == null) ? 0 : nullValues.hashCode());
+ result = prime * result + ((range == null) ? 0 : range.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ CoverageDimensionImpl other = (CoverageDimensionImpl) obj;
+ if (description == null) {
+ if (other.description != null)
+ return false;
+ } else if (!description.equals(other.description))
+ return false;
+ if (id == null) {
+ if (other.id != null)
+ return false;
+ } else if (!id.equals(other.id))
+ return false;
+ if (name == null) {
+ if (other.name != null)
+ return false;
+ } else if (!name.equals(other.name))
+ return false;
+ if (nullValues == null) {
+ if (other.nullValues != null)
+ return false;
+ } else if (!nullValues.equals(other.nullValues))
+ return false;
+ if (range == null) {
+ if (other.range != null)
+ return false;
+ } else if (!range.equals(other.range))
+ return false;
+ return true;
+ }
+
+
}
diff --git a/main/src/main/java/org/geoserver/catalog/impl/DefaultCatalogDAO.java b/main/src/main/java/org/geoserver/catalog/impl/DefaultCatalogDAO.java
new file mode 100644
index 0000000..08baea3
--- /dev/null
+++ b/main/src/main/java/org/geoserver/catalog/impl/DefaultCatalogDAO.java
@@ -0,0 +1,1102 @@
+package org.geoserver.catalog.impl;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.rmi.server.UID;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.collections.MultiHashMap;
+import org.geoserver.catalog.Catalog;
+import org.geoserver.catalog.CatalogDAO;
+import org.geoserver.catalog.CatalogInfo;
+import org.geoserver.catalog.CoverageDimensionInfo;
+import org.geoserver.catalog.CoverageInfo;
+import org.geoserver.catalog.DataStoreInfo;
+import org.geoserver.catalog.FeatureTypeInfo;
+import org.geoserver.catalog.LayerGroupInfo;
+import org.geoserver.catalog.LayerInfo;
+import org.geoserver.catalog.MapInfo;
+import org.geoserver.catalog.MetadataMap;
+import org.geoserver.catalog.NamespaceInfo;
+import org.geoserver.catalog.ResourceInfo;
+import org.geoserver.catalog.StoreInfo;
+import org.geoserver.catalog.StyleInfo;
+import org.geoserver.catalog.WMSLayerInfo;
+import org.geoserver.catalog.WorkspaceInfo;
+import org.geoserver.ows.util.ClassProperties;
+import org.geoserver.ows.util.OwsUtils;
+
+/**
+ * Default catalog dao implementation in which all objects are stored in memory.
+ *
+ * @author Justin Deoliveira, OpenGeo
+ *
+ * TODO: look for any exceptions, move them back to catlaog as they indicate logic
+ */
+public class DefaultCatalogDAO implements CatalogDAO {
+
+ public static WorkspaceInfo ANY_WORKSPACE = any(WorkspaceInfo.class);
+
+ public static NamespaceInfo ANY_NAMESPACE = any(NamespaceInfo.class);
+
+ @SuppressWarnings("unchecked")
+ static T any(Class clazz) {
+
+ Class proxyClass = Proxy.getProxyClass(clazz.getClassLoader(), clazz);
+ try {
+ return (T) proxyClass.getConstructor(
+ new Class[] { InvocationHandler.class }).newInstance(new Object[] {
+ new InvocationHandler() {
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ return null;
+ }
+ }
+ } );
+ }
+ catch( Exception e ) {
+ throw new RuntimeException( e );
+ }
+ }
+
+ /**
+ * Contains the stores keyed by implementation class
+ */
+ protected MultiHashMap/* */stores = new MultiHashMap();
+
+ /**
+ * The default store keyed by workspace id
+ */
+ protected Map defaultStores = new HashMap();
+
+ /**
+ * resources
+ */
+ protected MultiHashMap/* */resources = new MultiHashMap();
+
+ /**
+ * namespaces
+ */
+ protected HashMap namespaces = new HashMap();
+
+ /**
+ * workspaces
+ */
+ protected HashMap workspaces = new HashMap();
+
+ /**
+ * layers
+ */
+ protected List layers = new ArrayList();
+
+ /**
+ * maps
+ */
+ protected List maps = new ArrayList();
+
+ /**
+ * layer groups
+ */
+ protected List layerGroups = new ArrayList();
+
+ /**
+ * styles
+ */
+ protected List styles = new ArrayList();
+
+ /**
+ * the catalog
+ */
+ private CatalogImpl catalog;
+
+ public DefaultCatalogDAO(Catalog catalog) {
+ setCatalog(catalog);
+ }
+
+ public void setCatalog(Catalog catalog) {
+ this.catalog = (CatalogImpl) catalog;
+ }
+
+ public Catalog getCatalog() {
+ return null;
+ }
+
+ //
+ // Stores
+ //
+ public StoreInfo add(StoreInfo store) {
+ resolve(store);
+ synchronized(stores) {
+ stores.put(store.getClass(), store);
+ }
+ return ModificationProxy.create(store, StoreInfo.class);
+ }
+
+ public void remove(StoreInfo store) {
+ store = unwrap(store);
+
+ synchronized(stores) {
+ stores.remove(store.getClass(),store);
+ }
+ }
+
+ public void save(StoreInfo store) {
+ if ( store.getId() == null ) {
+ //add it instead of saving
+ add( store );
+ return;
+ }
+
+ saved(store);
+ }
+
+ public T detach(T store) {
+ return store;
+ }
+
+ public T getStore(String id, Class clazz) {
+ List l = lookup(clazz, stores);
+ for (Iterator i = l.iterator(); i.hasNext();) {
+ StoreInfo store = (StoreInfo) i.next();
+ if (id.equals(store.getId())) {
+ return ModificationProxy.create( (T) store, clazz );
+ }
+ }
+
+ return null;
+ }
+
+ public T getStoreByName(WorkspaceInfo workspace,
+ String name, Class clazz) {
+
+ List l = lookup(clazz, stores);
+ if (workspace == ANY_WORKSPACE) {
+ //do an exhaustive search through all workspaces
+ ArrayList matches = new ArrayList();
+ for (Iterator i = l.iterator(); i.hasNext();) {
+ T store = (T) i.next();
+ if ( name.equals( store.getName() ) ) {
+ matches.add( store );
+ }
+ }
+
+ if ( matches.size() == 1 ) {
+ return ModificationProxy.create( (T) matches.get( 0 ), clazz);
+ }
+ }
+ else {
+
+ for (Iterator i = l.iterator(); i.hasNext();) {
+ StoreInfo store = (StoreInfo) i.next();
+ if (name.equals(store.getName()) && store.getWorkspace().equals( workspace )) {
+ return ModificationProxy.create( (T) store, clazz );
+ }
+ }
+ }
+ return null;
+ }
+
+ public List getStoresByWorkspace(
+ WorkspaceInfo workspace, Class clazz) {
+
+ //TODO: support ANY_WORKSPACE?
+
+ if ( workspace == null ) {
+ workspace = getDefaultWorkspace();
+ }
+
+ List all = lookup(clazz, stores);
+ List matches = new ArrayList();
+
+ for (Iterator s = all.iterator(); s.hasNext();) {
+ StoreInfo store = (StoreInfo) s.next();
+ if (workspace.equals(store.getWorkspace())) {
+ matches.add(store);
+ }
+ }
+
+ return ModificationProxy.createList(matches,clazz);
+ }
+
+ public List getStores(Class clazz) {
+ return ModificationProxy.createList(lookup(clazz, stores) , clazz);
+ }
+
+ public DataStoreInfo getDefaultDataStore(WorkspaceInfo workspace) {
+ if(defaultStores.containsKey(workspace.getId())) {
+ DataStoreInfo defaultStore = defaultStores.get(workspace.getId());
+ return ModificationProxy.create(defaultStore, DataStoreInfo.class);
+ } else {
+ return null;
+ }
+ }
+
+ public void setDefaultDataStore(WorkspaceInfo workspace, DataStoreInfo store) {
+ DataStoreInfo old = defaultStores.get(workspace.getId());
+ synchronized(defaultStores) {
+ if (store != null) {
+ defaultStores.put(workspace.getId(), store);
+ }
+ else {
+ defaultStores.remove(workspace.getId());
+ }
+ }
+
+ //fire change event
+ catalog.fireModified(catalog,
+ Arrays.asList("defaultDataStore"), Arrays.asList(old), Arrays.asList(store));
+ }
+
+ //
+ // Resources
+ //
+ public ResourceInfo add(ResourceInfo resource) {
+ resolve(resource);
+ synchronized(resources) {
+ resources.put(resource.getClass(), resource);
+ }
+ return ModificationProxy.create(resource, ResourceInfo.class);
+ }
+
+ public void remove(ResourceInfo resource) {
+ resource = unwrap(resource);
+ synchronized(resources) {
+ resources.remove(resource.getClass(), resource);
+ }
+ }
+
+
+ public void save(ResourceInfo resource) {
+ saved(resource);
+ }
+
+ public T detach(T resource) {
+ return resource;
+ }
+
+ public T getResource(String id, Class clazz) {
+ List l = lookup(clazz, resources);
+ for (Iterator i = l.iterator(); i.hasNext();) {
+ ResourceInfo resource = (ResourceInfo) i.next();
+ if (id.equals(resource.getId())) {
+ return ModificationProxy.create((T) resource, clazz );
+ }
+ }
+
+ return null;
+ }
+
+ public T getResourceByName(NamespaceInfo namespace, String name, Class clazz) {
+
+ List l = lookup(clazz, resources);
+
+ if (namespace == ANY_NAMESPACE) {
+ //do an exhaustive lookup
+ List matches = new ArrayList();
+ for (Iterator i = l.iterator(); i.hasNext();) {
+ ResourceInfo resource = (ResourceInfo) i.next();
+ if (name.equals(resource.getName())) {
+ matches.add( resource );
+ }
+ }
+
+ if ( matches.size() == 1 ) {
+ return ModificationProxy.create( (T) matches.get( 0 ), clazz );
+ }
+ }
+ else {
+ for (Iterator i = l.iterator(); i.hasNext();) {
+ ResourceInfo resource = (ResourceInfo) i.next();
+ if (name.equals(resource.getName())) {
+ NamespaceInfo namespace1 = resource.getNamespace();
+ if (namespace1 != null && namespace1.equals( namespace )) {
+ return ModificationProxy.create( (T) resource, clazz );
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public List getResources(Class clazz) {
+ return ModificationProxy.createList( lookup(clazz,resources), clazz );
+ }
+
+ public List getResourcesByNamespace(NamespaceInfo namespace, Class clazz) {
+ //TODO: support ANY_NAMESPACE?
+
+ List all = lookup(clazz, resources);
+ List matches = new ArrayList();
+
+ if ( namespace == null ) {
+ namespace = getDefaultNamespace();
+ }
+
+ for (Iterator r = all.iterator(); r.hasNext();) {
+ ResourceInfo resource = (ResourceInfo) r.next();
+ if (namespace != null ) {
+ if (namespace.equals(resource.getNamespace())) {
+ matches.add( resource );
+ }
+ }
+ else if ( resource.getNamespace() == null ) {
+ matches.add(resource);
+ }
+ }
+
+ return ModificationProxy.createList( matches, clazz );
+ }
+
+ public T getResourceByStore(StoreInfo store,
+ String name, Class clazz) {
+ List all = lookup(clazz,resources);
+ for (Iterator r = all.iterator(); r.hasNext(); ) {
+ ResourceInfo resource = (ResourceInfo) r.next();
+ if ( name.equals( resource.getName() ) && store.equals( resource.getStore() ) ) {
+ return ModificationProxy.create((T)resource, clazz);
+ }
+ }
+
+ return null;
+ }
+
+ public List getResourcesByStore(
+ StoreInfo store, Class clazz) {
+ List all = lookup(clazz,resources);
+ List matches = new ArrayList();
+
+ for (Iterator r = all.iterator(); r.hasNext();) {
+ ResourceInfo resource = (ResourceInfo) r.next();
+ if (store.equals(resource.getStore())) {
+ matches.add(resource);
+ }
+ }
+
+ return ModificationProxy.createList( matches, clazz );
+ }
+
+ //
+ // Layers
+ //
+ public LayerInfo add(LayerInfo layer) {
+ resolve(layer);
+ synchronized(layers) {
+ layers.add(layer);
+ }
+
+ return ModificationProxy.create(layer, LayerInfo.class);
+ }
+
+ public void remove(LayerInfo layer) {
+ synchronized(layers) {
+ layers.remove(unwrap(layer));
+ }
+ }
+
+ public void save(LayerInfo layer) {
+ saved(layer);
+ }
+
+ public LayerInfo detach(LayerInfo layer) {
+ return layer;
+ }
+
+ public LayerInfo getLayer(String id) {
+ for (Iterator l = layers.iterator(); l.hasNext();) {
+ LayerInfo layer = (LayerInfo) l.next();
+ if (id.equals(layer.getId())) {
+ return ModificationProxy.create( layer, LayerInfo.class );
+ }
+ }
+
+ return null;
+ }
+
+ public LayerInfo getLayerByName(String name) {
+
+ for (Iterator l = layers.iterator(); l.hasNext();) {
+ LayerInfo layer = (LayerInfo) l.next();
+ if ( name.equals( layer.getName() ) ) {
+ return ModificationProxy.create( layer, LayerInfo.class );
+ }
+ }
+
+ return null;
+ }
+
+ public List getLayers(ResourceInfo resource) {
+ List matches = new ArrayList();
+ for (Iterator l = layers.iterator(); l.hasNext();) {
+ LayerInfo layer = (LayerInfo) l.next();
+ if ( resource.equals( layer.getResource() ) ) {
+ matches.add( layer );
+ }
+ }
+
+ return ModificationProxy.createList(matches,LayerInfo.class);
+ }
+
+ public List getLayers(StyleInfo style) {
+ List matches = new ArrayList();
+ for (Iterator l = layers.iterator(); l.hasNext();) {
+ LayerInfo layer = (LayerInfo) l.next();
+ if ( style.equals( layer.getDefaultStyle() ) || layer.getStyles().contains( style ) ) {
+ matches.add( layer );
+ }
+ }
+
+ return ModificationProxy.createList(matches,LayerInfo.class);
+ }
+
+ public List getLayers() {
+ return ModificationProxy.createList( new ArrayList(layers), LayerInfo.class );
+ }
+
+ //
+ // Maps
+ //
+ public MapInfo add(MapInfo map) {
+ resolve(map);
+ synchronized(maps) {
+ maps.add(map);
+ }
+
+ return ModificationProxy.create(map, MapInfo.class);
+ }
+
+ public void remove(MapInfo map) {
+ synchronized(maps) {
+ maps.remove(unwrap(map));
+ }
+ }
+
+ public void save(MapInfo map) {
+ saved( map );
+ }
+
+ public MapInfo detach(MapInfo map) {
+ return map;
+ }
+
+ public MapInfo getMap(String id) {
+ for (MapInfo map : maps) {
+ if (id.equals(map.getId())) {
+ return ModificationProxy.create(map,MapInfo.class);
+ }
+ }
+
+ return null;
+ }
+
+ public MapInfo getMapByName(String name) {
+ for (MapInfo map : maps) {
+ if (name.equals(map.getName())) {
+ return ModificationProxy.create(map,MapInfo.class);
+ }
+ }
+
+ return null;
+ }
+
+ public List getMaps() {
+ return ModificationProxy.createList( new ArrayList(maps), MapInfo.class );
+ }
+
+ //
+ // Layer groups
+ //
+ public LayerGroupInfo add (LayerGroupInfo layerGroup) {
+ resolve(layerGroup);
+ synchronized(layerGroups) {
+ layerGroups.add( layerGroup );
+ }
+ return ModificationProxy.create(layerGroup, LayerGroupInfo.class);
+ }
+
+ /* (non-Javadoc)
+ * @see org.geoserver.catalog.impl.CatalogDAO#remove(org.geoserver.catalog.LayerGroupInfo)
+ */
+ public void remove(LayerGroupInfo layerGroup) {
+ synchronized(layerGroups) {
+ layerGroups.remove( unwrap(layerGroup) );
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.geoserver.catalog.impl.CatalogDAO#save(org.geoserver.catalog.LayerGroupInfo)
+ */
+ public void save(LayerGroupInfo layerGroup) {
+ saved(layerGroup);
+ }
+
+ public LayerGroupInfo detach(LayerGroupInfo layerGroup) {
+ return layerGroup;
+ }
+
+ public List getLayerGroups() {
+ return ModificationProxy.createList( new ArrayList(layerGroups), LayerGroupInfo.class );
+ }
+
+ public LayerGroupInfo getLayerGroup(String id) {
+ for (LayerGroupInfo layerGroup : layerGroups ) {
+ if ( id.equals( layerGroup.getId() ) ) {
+ return ModificationProxy.create(layerGroup,LayerGroupInfo.class);
+ }
+ }
+
+ return null;
+ }
+
+ public LayerGroupInfo getLayerGroupByName(String name) {
+ for (LayerGroupInfo layerGroup : layerGroups ) {
+ if ( name.equals( layerGroup.getName() ) ) {
+ return ModificationProxy.create(layerGroup,LayerGroupInfo.class);
+ }
+ }
+
+ return null;
+ }
+
+ //
+ // Namespaces
+ //
+ public NamespaceInfo add(NamespaceInfo namespace) {
+ resolve(namespace);
+ synchronized(namespaces) {
+ namespaces.put(namespace.getPrefix(),namespace);
+ }
+
+ return ModificationProxy.create(namespace, NamespaceInfo.class);
+ }
+
+ public void remove(NamespaceInfo namespace) {
+ synchronized(namespaces) {
+ NamespaceInfo defaultNamespace = getDefaultNamespace();
+ if (namespace.equals(defaultNamespace)) {
+ namespaces.remove(null);
+ namespaces.remove(Catalog.DEFAULT);
+ }
+
+ namespaces.remove(namespace.getPrefix());
+ }
+ }
+
+ public void save(NamespaceInfo namespace) {
+ ModificationProxy h =
+ (ModificationProxy) Proxy.getInvocationHandler(namespace);
+
+ NamespaceInfo ns = (NamespaceInfo) h.getProxyObject();
+ if ( !namespace.getPrefix().equals( ns.getPrefix() ) ) {
+ synchronized (namespaces) {
+ namespaces.remove( ns.getPrefix() );
+ namespaces.put( namespace.getPrefix(), ns );
+ }
+ }
+
+ saved(namespace);
+ }
+
+ public NamespaceInfo detach(NamespaceInfo namespace) {
+ return namespace;
+ }
+
+ public NamespaceInfo getDefaultNamespace() {
+ return namespaces.containsKey(null) ?
+ ModificationProxy.create(namespaces.get( null ),NamespaceInfo.class) : null;
+ }
+
+ public void setDefaultNamespace(NamespaceInfo defaultNamespace) {
+ NamespaceInfo ns = namespaces.get(defaultNamespace.getPrefix());
+ NamespaceInfo old = namespaces.get(null);
+ namespaces.put( null, ns );
+ namespaces.put( Catalog.DEFAULT, ns );
+
+ //fire change event
+ catalog.fireModified(catalog,
+ Arrays.asList("defaultNamespace"), Arrays.asList(old), Arrays.asList(defaultNamespace));
+
+ }
+
+ public NamespaceInfo getNamespace(String id) {
+ for (NamespaceInfo namespace : namespaces.values() ) {
+ if (id.equals(namespace.getId())) {
+ return ModificationProxy.create( namespace, NamespaceInfo.class );
+ }
+ }
+
+ return null;
+ }
+
+ public NamespaceInfo getNamespaceByPrefix(String prefix) {
+ NamespaceInfo ns = namespaces.get( prefix );
+ return ns != null ? ModificationProxy.create(ns, NamespaceInfo.class ) : null;
+ }
+
+ public NamespaceInfo getNamespaceByURI(String uri) {
+ for (NamespaceInfo namespace : namespaces.values() ) {
+ if (uri.equals(namespace.getURI())) {
+ return ModificationProxy.create( namespace, NamespaceInfo.class );
+ }
+ }
+
+ return null;
+ }
+
+ public List getNamespaces() {
+ ArrayList ns = new ArrayList();
+ for ( Map.Entry e : namespaces.entrySet() ) {
+ if ( e.getKey() == null || e.getKey().equals(Catalog.DEFAULT))
+ continue;
+ ns.add( e.getValue() );
+ }
+
+ return ModificationProxy.createList( ns, NamespaceInfo.class );
+ }
+
+ //
+ // Workspaces
+ //
+ // Workspace methods
+ public WorkspaceInfo add(WorkspaceInfo workspace) {
+ resolve(workspace);
+ synchronized (workspaces) {
+ workspaces.put( workspace.getName(), workspace );
+ }
+ return ModificationProxy.create(workspace, WorkspaceInfo.class);
+ }
+
+ public void remove(WorkspaceInfo workspace) {
+ synchronized(workspaces) {
+ workspaces.remove( workspace.getName() );
+ }
+ }
+
+ public void save(WorkspaceInfo workspace) {
+ ModificationProxy h =
+ (ModificationProxy) Proxy.getInvocationHandler(workspace);
+
+ WorkspaceInfo ws = (WorkspaceInfo) h.getProxyObject();
+ if ( !workspace.getName().equals( ws.getName() ) ) {
+ synchronized (workspaces) {
+ workspaces.remove( ws.getName() );
+ workspaces.put( workspace.getName(), ws );
+ }
+ }
+
+ saved(workspace);
+ }
+
+ public WorkspaceInfo detach(WorkspaceInfo workspace) {
+ return workspace;
+ }
+
+ public WorkspaceInfo getDefaultWorkspace() {
+ return workspaces.containsKey( null ) ?
+ ModificationProxy.create( workspaces.get( null ), WorkspaceInfo.class ) : null;
+ }
+
+ public void setDefaultWorkspace(WorkspaceInfo workspace) {
+ WorkspaceInfo old = workspaces.get(null);
+
+ synchronized(workspaces) {
+ if (workspace != null) {
+ WorkspaceInfo ws = workspaces.get(workspace.getName());
+ workspaces.put( null, ws );
+ workspaces.put( "default", ws );
+ }
+ else {
+ workspaces.remove(null);
+ workspaces.remove("default");
+ }
+
+ }
+
+ //fire change event
+ catalog.fireModified(catalog,
+ Arrays.asList("defaultWorkspace"), Arrays.asList(old), Arrays.asList(workspace));
+ }
+
+ public List getWorkspaces() {
+ ArrayList ws = new ArrayList();
+
+ //strip out default namespace
+ for ( Map.Entry e : workspaces.entrySet() ) {
+ if ( e.getKey() == null || e.getKey().equals(Catalog.DEFAULT) ) {
+ continue;
+ }
+
+ ws.add( e.getValue() );
+ }
+
+ return ModificationProxy.createList( ws, WorkspaceInfo.class );
+ }
+
+ public WorkspaceInfo getWorkspace(String id) {
+ for ( WorkspaceInfo ws : workspaces.values() ) {
+ if ( id.equals( ws.getId() ) ) {
+ return ModificationProxy.create(ws,WorkspaceInfo.class);
+ }
+ }
+
+ return null;
+ }
+
+ public WorkspaceInfo getWorkspaceByName(String name) {
+ return workspaces.containsKey(name) ?
+ ModificationProxy.create( workspaces.get( name ), WorkspaceInfo.class ) : null;
+ }
+
+ //
+ // Styles
+ //
+ public StyleInfo add(StyleInfo style) {
+ resolve(style);
+ synchronized(styles) {
+ styles.add(style);
+ }
+ return ModificationProxy.create(style, StyleInfo.class);
+ }
+
+ public void remove(StyleInfo style) {
+ synchronized(styles) {
+ styles.remove(unwrap(style));
+ }
+ }
+
+ public void save(StyleInfo style) {
+ saved( style );
+ }
+
+ public StyleInfo detach(StyleInfo style) {
+ return style;
+ }
+
+ public StyleInfo getStyle(String id) {
+ for (Iterator s = styles.iterator(); s.hasNext();) {
+ StyleInfo style = (StyleInfo) s.next();
+ if (id.equals(style.getId())) {
+ return ModificationProxy.create(style,StyleInfo.class);
+ }
+ }
+
+ return null;
+ }
+
+ public StyleInfo getStyleByName(String name) {
+ for (Iterator s = styles.iterator(); s.hasNext();) {
+ StyleInfo style = (StyleInfo) s.next();
+ if (name.equals(style.getName())) {
+ return ModificationProxy.create(style,StyleInfo.class);
+ }
+ }
+
+ return null;
+ }
+
+ public List getStyles() {
+ return ModificationProxy.createList(styles,StyleInfo.class);
+ }
+
+ //
+ // Utilities
+ //
+ public static T unwrap(T obj) {
+ return ModificationProxy.unwrap(obj);
+ }
+
+ protected void saved(CatalogInfo object) {
+ //this object is a proxy
+ ModificationProxy h =
+ (ModificationProxy) Proxy.getInvocationHandler(object);
+
+ //get the real object
+ CatalogInfo real = (CatalogInfo) h.getProxyObject();
+
+ //fire out what changed
+ List propertyNames = h.getPropertyNames();
+ List newValues = h.getNewValues();
+ List oldValues = h.getOldValues();
+
+ //TODO: protect this original object, perhaps with another proxy
+ catalog.fireModified( real, propertyNames, oldValues, newValues );
+
+ //commit to the original object
+ h.commit();
+
+ //resolve to do a sync on the object
+ //syncIdWithName(real);
+
+ //fire the post modify event
+ catalog.firePostModified( real );
+ }
+
+ List lookup(Class clazz, MultiHashMap map) {
+ ArrayList result = new ArrayList();
+ for (Iterator k = map.keySet().iterator(); k.hasNext();) {
+ Class key = (Class) k.next();
+ if (clazz.isAssignableFrom(key)) {
+ result.addAll(map.getCollection(key));
+ }
+ }
+
+ return result;
+ }
+
+ public void dispose() {
+ if ( stores != null ) stores.clear();
+ if ( defaultStores != null ) defaultStores.clear();
+ if ( resources != null ) resources.clear();
+ if ( namespaces != null ) namespaces.clear();
+ if ( workspaces != null ) workspaces.clear();
+ if ( layers != null ) layers.clear();
+ if ( layerGroups != null ) layerGroups.clear();
+ if ( maps != null ) maps.clear();
+ if ( styles != null ) styles.clear();
+ }
+
+ public void resolve() {
+ //JD creation checks are done here b/c when xstream depersists
+ // some members may be left null
+
+ //workspaces
+ if ( workspaces == null ) {
+ workspaces = new HashMap();
+ }
+ for ( WorkspaceInfo ws : workspaces.values() ) {
+ resolve(ws);
+ }
+
+ //namespaces
+ if ( namespaces == null ) {
+ namespaces = new HashMap();
+ }
+ for ( NamespaceInfo ns : namespaces.values() ) {
+ resolve(ns);
+ }
+
+ //stores
+ if ( stores == null ) {
+ stores = new MultiHashMap();
+ }
+ for ( Object o : stores.values() ) {
+ resolve((StoreInfoImpl)o);
+ }
+
+ //styles
+ if ( styles == null ) {
+ styles = new ArrayList();
+ }
+ for ( StyleInfo s : styles ) {
+ resolve(s);
+ }
+
+ //resources
+ if ( resources == null ) {
+ resources = new MultiHashMap();
+ }
+ for( Object o : resources.values() ) {
+ resolve((ResourceInfo)o);
+ }
+
+ //layers
+ if ( layers == null ) {
+ layers = new ArrayList();
+ }
+ for ( LayerInfo l : layers ) {
+ resolve(l);
+ }
+
+ //layer groups
+ if ( layerGroups == null ) {
+ layerGroups = new ArrayList();
+ }
+ for ( LayerGroupInfo lg : layerGroups ) {
+ resolve(lg);
+ }
+
+ //maps
+ if ( maps == null ) {
+ maps = new ArrayList();
+ }
+ for ( MapInfo m : maps ) {
+ resolve(m);
+ }
+ }
+
+ protected void resolve(WorkspaceInfo workspace) {
+ setId(workspace);
+ }
+
+ protected void resolve(NamespaceInfo namespace) {
+ setId(namespace);
+ }
+
+ protected void resolve(StoreInfo store) {
+ setId(store);
+ StoreInfoImpl s = (StoreInfoImpl) store;
+
+ //resolve the workspace
+ WorkspaceInfo resolved = ResolvingProxy.resolve( catalog, s.getWorkspace());
+ if ( resolved != null ) {
+ resolved = unwrap(resolved);
+ s.setWorkspace( resolved );
+ }
+ else {
+ //this means the workspace has not yet been added to the catalog, keep the proxy around
+ }
+ }
+
+ protected void resolve(ResourceInfo resource) {
+ setId(resource);
+ ResourceInfoImpl r = (ResourceInfoImpl) resource;
+
+ //resolve the store
+ StoreInfo store = ResolvingProxy.resolve( catalog, r.getStore() );
+ if ( store != null ) {
+ store = unwrap(store);
+ r.setStore(store);
+ }
+
+ //resolve the namespace
+ NamespaceInfo namespace = ResolvingProxy.resolve( catalog, r.getNamespace() );
+ if (namespace != null) {
+ namespace = unwrap(namespace);
+ r.setNamespace(namespace);
+ }
+ }
+
+ protected void resolve(LayerInfo layer) {
+ setId(layer);
+
+ ResourceInfo resource = ResolvingProxy.resolve(catalog, layer.getResource());
+ if (resource != null) {
+ resource = unwrap(resource);
+ layer.setResource(resource);
+ }
+
+ StyleInfo style = ResolvingProxy.resolve(catalog, layer.getDefaultStyle());
+ if (style != null) {
+ style = unwrap(style);
+ layer.setDefaultStyle(style);
+ }
+
+ LinkedHashSet styles = new LinkedHashSet();
+ for (StyleInfo s : layer.getStyles()) {
+ s = ResolvingProxy.resolve(catalog, s);
+ s = unwrap(s);
+ styles.add(s);
+ }
+ ((LayerInfoImpl)layer).setStyles(styles);
+ }
+
+ protected void resolve(LayerGroupInfo layerGroup) {
+ setId(layerGroup);
+
+ LayerGroupInfoImpl lg = (LayerGroupInfoImpl) layerGroup;
+
+ for ( int i = 0; i < lg.getLayers().size(); i++ ) {
+ LayerInfo l = lg.getLayers().get( i );
+ LayerInfo resolved = unwrap(ResolvingProxy.resolve( catalog, l ));
+ lg.getLayers().set( i, resolved );
+ }
+
+ for ( int i = 0; i < lg.getStyles().size(); i++ ) {
+ StyleInfo s = lg.getStyles().get( i );
+ if(s != null) {
+ StyleInfo resolved = unwrap(ResolvingProxy.resolve( catalog, s ));
+ lg.getStyles().set( i, resolved );
+ }
+ }
+
+ }
+
+ protected void resolve(StyleInfo style) {
+ setId(style);
+ }
+
+ protected void resolve(MapInfo map) {
+ setId(map);
+ }
+
+ protected void setId( Object o ) {
+ if ( OwsUtils.get( o, "id") == null ) {
+ String uid = new UID().toString();
+ OwsUtils.set( o, "id", o.getClass().getSimpleName() + "-"+uid );
+ }
+ }
+
+ public void syncTo(CatalogDAO dao) {
+ if (dao instanceof DefaultCatalogDAO) {
+ //do an optimized sync
+ DefaultCatalogDAO other = (DefaultCatalogDAO) dao;
+
+ other.stores = stores;
+ other.defaultStores = defaultStores;
+ other.resources = resources;
+ other.namespaces = namespaces;
+ other.workspaces = workspaces;
+ other.layers = layers;
+ other.maps = maps;
+ other.layerGroups = layerGroups;
+ other.styles = styles;
+ }
+ else {
+ //do a manual import
+ for (Map.Entry e : workspaces.entrySet()) {
+ if (e.getKey() != null && !"default".equals(e.getKey())) {
+ dao.add(e.getValue());
+ }
+ }
+ for (Map.Entry e : namespaces.entrySet()) {
+ if (e.getKey() != null && !"default".equals(e.getKey())) {
+ dao.add(e.getValue());
+ }
+ }
+
+ for (Iterator k = stores.keySet().iterator(); k.hasNext();) {
+ Class key = (Class) k.next();
+ Collection val = stores.getCollection(key);
+ for (StoreInfo s : val) {
+ dao.add(s);
+ }
+ }
+
+ for (Iterator k = resources.keySet().iterator(); k.hasNext();) {
+ Class key = (Class) k.next();
+ Collection val = resources.getCollection(key);
+ for (ResourceInfo r : val) {
+ dao.add(r);
+ }
+ }
+
+ for (StyleInfo s : styles) { dao.add(s); }
+ for (LayerInfo l : layers) { dao.add(l); }
+ for (LayerGroupInfo lg : layerGroups) { dao.add(lg); }
+ for (MapInfo m : maps) { dao.add(m); }
+
+ if (workspaces.containsKey(null)) {
+ dao.setDefaultWorkspace(workspaces.get(null));
+ }
+ if (namespaces.containsKey(null)) {
+ dao.setDefaultNamespace(namespaces.get(null));
+ }
+
+ for (Map.Entry e : defaultStores.entrySet()) {
+ WorkspaceInfo ws = workspaces.get(e.getKey());
+ dao.setDefaultDataStore(ws, e.getValue());
+ }
+ }
+
+ }
+}
+
diff --git a/main/src/main/java/org/geoserver/catalog/impl/LayerInfoImpl.java b/main/src/main/java/org/geoserver/catalog/impl/LayerInfoImpl.java
index ea15632..317aa9d 100644
--- a/main/src/main/java/org/geoserver/catalog/impl/LayerInfoImpl.java
+++ b/main/src/main/java/org/geoserver/catalog/impl/LayerInfoImpl.java
@@ -56,6 +56,9 @@ public class LayerInfoImpl implements LayerInfo {
}
public String getName() {
+ if (resource == null) {
+ throw new NullPointerException("Unable to get Layer name without an underlying resource");
+ }
return resource.getName();
// TODO: uncomment back when resource/publish split is complete
// return name;
@@ -65,6 +68,10 @@ public class LayerInfoImpl implements LayerInfo {
// TODO: remove this log and reinstate field assignment when resource/publish split is complete
LOGGER.log(Level.FINE, "Warning, some code is setting the LayerInfo name, but that will be ignored");
this.name = name;
+
+ if (resource == null) {
+ throw new NullPointerException("Layer name must not be set without an underlying resource");
+ }
resource.setName(name);
}
diff --git a/main/src/main/java/org/geoserver/catalog/impl/StoreInfoImpl.java b/main/src/main/java/org/geoserver/catalog/impl/StoreInfoImpl.java
index 3929779..7b13caf 100644
--- a/main/src/main/java/org/geoserver/catalog/impl/StoreInfoImpl.java
+++ b/main/src/main/java/org/geoserver/catalog/impl/StoreInfoImpl.java
@@ -43,6 +43,8 @@ public abstract class StoreInfoImpl implements StoreInfo {
protected Throwable error;
+ protected boolean _default;
+
protected StoreInfoImpl() {
}
@@ -151,6 +153,13 @@ public abstract class StoreInfoImpl implements StoreInfo {
this.error = error;
}
+ public boolean isDefault() {
+ return _default;
+ }
+
+ public void setDefault(boolean _default) {
+ this._default = _default;
+ }
public int hashCode() {
final int prime = 31;
int result = 1;
diff --git a/main/src/main/java/org/geoserver/catalog/impl/WMSLayerInfoImpl.java b/main/src/main/java/org/geoserver/catalog/impl/WMSLayerInfoImpl.java
index 49d2df2..df70e4f 100644
--- a/main/src/main/java/org/geoserver/catalog/impl/WMSLayerInfoImpl.java
+++ b/main/src/main/java/org/geoserver/catalog/impl/WMSLayerInfoImpl.java
@@ -15,6 +15,10 @@ import org.opengis.util.ProgressListener;
@SuppressWarnings("serial")
public class WMSLayerInfoImpl extends ResourceInfoImpl implements WMSLayerInfo {
+
+ protected WMSLayerInfoImpl() {
+ }
+
public WMSLayerInfoImpl(CatalogImpl catalog) {
super(catalog);
}
diff --git a/main/src/main/java/org/geoserver/catalog/impl/WMSStoreInfoImpl.java b/main/src/main/java/org/geoserver/catalog/impl/WMSStoreInfoImpl.java
index f6fd588..deea114 100644
--- a/main/src/main/java/org/geoserver/catalog/impl/WMSStoreInfoImpl.java
+++ b/main/src/main/java/org/geoserver/catalog/impl/WMSStoreInfoImpl.java
@@ -16,6 +16,9 @@ public class WMSStoreInfoImpl extends StoreInfoImpl implements WMSStoreInfo {
String capabilitiesURL;
+ protected WMSStoreInfoImpl() {
+ }
+
public WMSStoreInfoImpl(CatalogImpl catalog) {
super(catalog);
}
diff --git a/main/src/main/java/org/geoserver/config/DefaultGeoServerDAO.java b/main/src/main/java/org/geoserver/config/DefaultGeoServerDAO.java
new file mode 100644
index 0000000..a64d4a0
--- /dev/null
+++ b/main/src/main/java/org/geoserver/config/DefaultGeoServerDAO.java
@@ -0,0 +1,166 @@
+package org.geoserver.config;
+
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+
+import org.geoserver.catalog.MetadataMap;
+import org.geoserver.catalog.impl.ModificationProxy;
+import org.geoserver.config.impl.CoverageAccessInfoImpl;
+import org.geoserver.config.impl.GeoServerInfoImpl;
+
+public class DefaultGeoServerDAO implements GeoServerDAO {
+
+ GeoServerInfo global;
+ LoggingInfo logging;
+ List services = new ArrayList();
+
+ GeoServer geoServer;
+
+ public DefaultGeoServerDAO(GeoServer geoServer) {
+ this.geoServer = geoServer;
+ this.global = geoServer.getFactory().createGlobal();
+ this.logging = geoServer.getFactory().createLogging();
+ }
+
+ public GeoServer getGeoServer() {
+ return geoServer;
+ }
+
+ public void setGeoServer(GeoServer geoServer) {
+ this.geoServer = geoServer;
+ }
+
+ public GeoServerInfo getGlobal() {
+ if ( global == null ) {
+ return null;
+ }
+
+ return ModificationProxy.create( global, GeoServerInfo.class );
+ }
+
+ public void setGlobal(GeoServerInfo global) {
+ resolve(global);
+ this.global = global;
+ }
+
+ public void save(GeoServerInfo global) {
+ ModificationProxy proxy =
+ (ModificationProxy) Proxy.getInvocationHandler( global );
+
+ List propertyNames = proxy.getPropertyNames();
+ List oldValues = proxy.getOldValues();
+ List newValues = proxy.getNewValues();
+
+ geoServer.fireGlobalModified(global, propertyNames, oldValues, newValues);
+
+ proxy.commit();
+ }
+
+ public LoggingInfo getLogging() {
+ if ( logging == null ) {
+ return null;
+ }
+
+ return ModificationProxy.create( logging, LoggingInfo.class );
+ }
+
+ public void setLogging(LoggingInfo logging) {
+ this.logging = logging;
+ }
+
+ public void save(LoggingInfo logging) {
+ ModificationProxy proxy =
+ (ModificationProxy) Proxy.getInvocationHandler( logging );
+
+ List propertyNames = proxy.getPropertyNames();
+ List oldValues = proxy.getOldValues();
+ List newValues = proxy.getNewValues();
+
+ geoServer.fireLoggingModified(logging, propertyNames, oldValues, newValues);
+
+ proxy.commit();
+ }
+
+ public void add(ServiceInfo service) {
+ //may be adding a proxy, need to unwrap
+ service = unwrap(service);
+ service.setGeoServer(geoServer);
+ services.add( service );
+ }
+
+ public void save(ServiceInfo service) {
+ ModificationProxy proxy =
+ (ModificationProxy) Proxy.getInvocationHandler( service );
+
+ List propertyNames = proxy.getPropertyNames();
+ List oldValues = proxy.getOldValues();
+ List newValues = proxy.getNewValues();
+
+ geoServer.fireServiceModified(service, propertyNames, oldValues, newValues);
+
+ proxy.commit();
+ }
+
+ public void remove(ServiceInfo service) {
+ services.remove( service );
+ }
+
+ public T getService(Class clazz) {
+ for ( ServiceInfo si : services ) {
+ if( clazz.isAssignableFrom( si.getClass() ) ) {
+ return ModificationProxy.create( (T) si, clazz );
+ }
+ }
+
+ return null;
+ }
+
+ public T getService(String id, Class clazz) {
+ for ( ServiceInfo si : services ) {
+ if( id.equals( si.getId() ) ) {
+ return ModificationProxy.create( (T) si, clazz );
+ }
+ }
+
+ return null;
+ }
+
+ public T getServiceByName(String name, Class clazz) {
+ for ( ServiceInfo si : services ) {
+ if( name.equals( si.getName() ) ) {
+ return ModificationProxy.create( (T) si, clazz );
+ }
+ }
+
+ return null;
+ }
+
+ public Collection extends ServiceInfo> getServices() {
+ return ModificationProxy.createList( services, ServiceInfo.class );
+ }
+
+ public void dispose() {
+ if ( global != null ) global.dispose();
+ if ( services != null ) services.clear();
+ }
+
+ public static T unwrap(T obj) {
+ return ModificationProxy.unwrap(obj);
+ }
+
+ protected void resolve(GeoServerInfo info) {
+ GeoServerInfoImpl global = (GeoServerInfoImpl) info;
+ if(global.getMetadata() == null) {
+ global.setMetadata(new MetadataMap());
+ }
+ if(global.getClientProperties() == null) {
+ global.setClientProperties(new HashMap