Java tutorial
/* Copyright (c) 2001 - 2008 TOPP - www.openplans.org. All rights reserved. * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ 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.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.CatalogException; import org.geoserver.catalog.CatalogFactory; import org.geoserver.catalog.CatalogInfo; import org.geoserver.catalog.CatalogVisitor; import org.geoserver.catalog.CoverageDimensionInfo; import org.geoserver.catalog.CoverageInfo; import org.geoserver.catalog.CoverageStoreInfo; 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.ResourcePool; import org.geoserver.catalog.StoreInfo; import org.geoserver.catalog.StyleInfo; import org.geoserver.catalog.WorkspaceInfo; import org.geoserver.catalog.event.CatalogAddEvent; import org.geoserver.catalog.event.CatalogEvent; import org.geoserver.catalog.event.CatalogListener; import org.geoserver.catalog.event.CatalogModifyEvent; import org.geoserver.catalog.event.CatalogPostModifyEvent; import org.geoserver.catalog.event.CatalogRemoveEvent; import org.geoserver.catalog.event.impl.CatalogAddEventImpl; import org.geoserver.catalog.event.impl.CatalogModifyEventImpl; import org.geoserver.catalog.event.impl.CatalogPostModifyEventImpl; import org.geoserver.catalog.event.impl.CatalogRemoveEventImpl; import org.geoserver.ows.util.ClassProperties; import org.geoserver.ows.util.OwsUtils; import org.geoserver.platform.GeoServerResourceLoader; import org.geotools.util.logging.Logging; import org.opengis.feature.type.Name; /** * A default catalog implementation that is memory based. * * @author Justin Deoliveira, The Open Planning Project * */ public class CatalogImpl implements Catalog { /** * logger */ private static final Logger LOGGER = Logging.getLogger(CatalogImpl.class); /** * stores */ protected MultiHashMap/* <Class> */ stores = new MultiHashMap(); /** * resources */ protected MultiHashMap/* <Class> */ resources = new MultiHashMap(); /** * namespaces */ protected HashMap<String, NamespaceInfo> namespaces = new HashMap<String, NamespaceInfo>(); /** * workspaces */ protected HashMap<String, WorkspaceInfo> workspaces = new HashMap<String, WorkspaceInfo>(); /** * layers */ protected List<LayerInfo> layers = new ArrayList(); /** * maps */ protected List<MapInfo> maps = new ArrayList<MapInfo>(); /** * layer groups */ protected List<LayerGroupInfo> layerGroups = new ArrayList<LayerGroupInfo>(); /** * styles */ protected List<StyleInfo> styles = new ArrayList(); /** * listeners */ protected List listeners = new ArrayList(); /** * resources */ protected ResourcePool resourcePool; protected GeoServerResourceLoader resourceLoader; public CatalogImpl() { resourcePool = new ResourcePool(this); } public String getId() { return "catalog"; } public CatalogFactory getFactory() { return new CatalogFactoryImpl(this); } // Store methods public void add(StoreInfo store) { if (store.getWorkspace() == null) { store.setWorkspace(getDefaultWorkspace()); } validate(store, true); resolve(store); stores.put(store.getClass(), store); added(store); } void validate(StoreInfo store, boolean isNew) { if (isNull(store.getName())) { throw new IllegalArgumentException("Store name must not be null"); } if (store.getWorkspace() == null) { throw new IllegalArgumentException("Store must be part of a workspace"); } WorkspaceInfo workspace = store.getWorkspace(); StoreInfo existing = getStoreByName(workspace, store.getName(), StoreInfo.class); if (existing != null && !existing.getId().equals(store.getId())) { String msg = "Store '" + store.getName() + "' already exists in workspace '" + workspace.getName() + "'"; throw new IllegalArgumentException(msg); } } public void remove(StoreInfo store) { if (!getResourcesByStore(store, ResourceInfo.class).isEmpty()) { throw new IllegalArgumentException("Unable to delete non-empty store."); } store = unwrap(store); stores.remove(store.getClass(), store); removed(store); } public void save(StoreInfo store) { validate(store, false); if (store.getId() == null) { //add it instead of saving add(store); return; } saved(store); } public <T extends StoreInfo> T getStore(String id, Class<T> 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; } } return null; } public <T extends StoreInfo> T getStoreByName(String name, Class<T> 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; } public <T extends StoreInfo> T getStoreByName(WorkspaceInfo workspace, String name, Class<T> clazz) { if (workspace == null) { workspace = getDefaultWorkspace(); } 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); } } return null; } public <T extends StoreInfo> T getStoreByName(String workspaceName, String name, Class<T> clazz) { return getStoreByName(workspaceName != null ? getWorkspaceByName(workspaceName) : null, name, clazz); } public <T extends StoreInfo> List<T> getStoresByWorkspace(String workspaceName, Class<T> clazz) { WorkspaceInfo workspace = null; if (workspaceName != null) { workspace = getWorkspaceByName(workspaceName); if (workspace == null) { return Collections.EMPTY_LIST; } } return getStoresByWorkspace(workspace, clazz); } public <T extends StoreInfo> List<T> getStoresByWorkspace(WorkspaceInfo workspace, Class<T> 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); } public List getStores(Class clazz) { return ModificationProxy.createList(lookup(clazz, stores), clazz); } public DataStoreInfo getDataStore(String id) { return (DataStoreInfo) getStore(id, DataStoreInfo.class); } public DataStoreInfo getDataStoreByName(String name) { return (DataStoreInfo) getStoreByName(name, DataStoreInfo.class); } public DataStoreInfo getDataStoreByName(String workspaceName, String name) { return (DataStoreInfo) getStoreByName(workspaceName, name, DataStoreInfo.class); } public DataStoreInfo getDataStoreByName(WorkspaceInfo workspace, String name) { return (DataStoreInfo) getStoreByName(workspace, name, DataStoreInfo.class); } public List<DataStoreInfo> getDataStoresByWorkspace(String workspaceName) { return getStoresByWorkspace(workspaceName, DataStoreInfo.class); } public List<DataStoreInfo> getDataStoresByWorkspace(WorkspaceInfo workspace) { return getStoresByWorkspace(workspace, DataStoreInfo.class); } public List getDataStores() { return getStores(DataStoreInfo.class); } public CoverageStoreInfo getCoverageStore(String id) { return (CoverageStoreInfo) getStore(id, CoverageStoreInfo.class); } public CoverageStoreInfo getCoverageStoreByName(String name) { return (CoverageStoreInfo) getStoreByName(name, CoverageStoreInfo.class); } public CoverageStoreInfo getCoverageStoreByName(String workspaceName, String name) { return getStoreByName(workspaceName, name, CoverageStoreInfo.class); } public CoverageStoreInfo getCoverageStoreByName(WorkspaceInfo workspace, String name) { return getStoreByName(workspace, name, CoverageStoreInfo.class); } public List<CoverageStoreInfo> getCoverageStoresByWorkspace(String workspaceName) { return getStoresByWorkspace(workspaceName, CoverageStoreInfo.class); } public List<CoverageStoreInfo> getCoverageStoresByWorkspace(WorkspaceInfo workspace) { return getStoresByWorkspace(workspace, CoverageStoreInfo.class); } public List getCoverageStores() { return getStores(CoverageStoreInfo.class); } // Resource methods public void add(ResourceInfo resource) { if (resource.getNamespace() == null) { //default to default namespace resource.setNamespace(getDefaultNamespace()); } validate(resource, true); resolve(resource); resources.put(resource.getClass(), resource); added(resource); } void validate(ResourceInfo resource, boolean isNew) { if (isNull(resource.getName())) { throw new NullPointerException("Resource name must not be null"); } if (resource.getStore() == null) { throw new IllegalArgumentException("Resource must be part of a store"); } if (resource.getNamespace() == null) { throw new IllegalArgumentException("Resource must be part of a namespace"); } StoreInfo store = resource.getStore(); ResourceInfo existing = getResourceByStore(store, resource.getName(), ResourceInfo.class); if (existing != null && !existing.getId().equals(resource.getId())) { String msg = "Resource named '" + resource.getName() + "' already exists in store: '" + store.getName() + "'"; throw new IllegalArgumentException(msg); } NamespaceInfo namespace = resource.getNamespace(); existing = getResourceByName(namespace, resource.getName(), ResourceInfo.class); if (existing != null && !existing.getId().equals(resource.getId())) { String msg = "Resource named '" + resource.getName() + "' already exists in namespace: '" + namespace.getPrefix() + "'"; throw new IllegalArgumentException(msg); } } public void remove(ResourceInfo resource) { //ensure no references to the resource if (!getLayers(resource).isEmpty()) { throw new IllegalArgumentException("Unable to delete resource referenced by layer"); } resource = unwrap(resource); resources.remove(resource.getClass(), resource); removed(resource); } public void save(ResourceInfo resource) { validate(resource, false); saved(resource); } public <T extends ResourceInfo> T getResource(String id, Class<T> 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 extends ResourceInfo> T getResourceByName(String ns, String name, Class<T> 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); } } 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 (matches.size() == 1) { return ModificationProxy.create((T) matches.get(0), clazz); } } return null; } public <T extends ResourceInfo> T getResourceByName(NamespaceInfo ns, String name, Class<T> clazz) { return getResourceByName(ns != null ? ns.getPrefix() : null, name, clazz); } public <T extends ResourceInfo> T getResourceByName(Name name, Class<T> clazz) { return getResourceByName(name.getNamespaceURI(), name.getLocalPart(), clazz); } public <T extends ResourceInfo> T getResourceByName(String name, Class<T> clazz) { ResourceInfo resource; // check is the name is a fully qualified one int colon = name.indexOf(':'); if (colon != -1) { String ns = name.substring(0, colon); String localName = name.substring(colon + 1); return getResourceByName(ns, localName, clazz); } else { return getResourceByName((String) null, name, clazz); } } public List getResources(Class clazz) { return ModificationProxy.createList(lookup(clazz, resources), 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); } public <T extends ResourceInfo> List<T> getResourcesByNamespace(String namespace, Class<T> clazz) { if (namespace == null) { return getResourcesByNamespace((NamespaceInfo) null, clazz); } NamespaceInfo ns = getNamespaceByPrefix(namespace); if (ns == null) { ns = getNamespaceByURI(namespace); } if (ns == null) { return Collections.EMPTY_LIST; } return getResourcesByNamespace(ns, clazz); } public <T extends ResourceInfo> T getResourceByStore(StoreInfo store, String name, Class<T> 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 <T extends ResourceInfo> List<T> getResourcesByStore(StoreInfo store, Class<T> 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); } public FeatureTypeInfo getFeatureType(String id) { return (FeatureTypeInfo) getResource(id, FeatureTypeInfo.class); } public FeatureTypeInfo getFeatureTypeByName(String ns, String name) { return (FeatureTypeInfo) getResourceByName(ns, name, FeatureTypeInfo.class); } public FeatureTypeInfo getFeatureTypeByName(NamespaceInfo ns, String name) { return getResourceByName(ns, name, FeatureTypeInfo.class); } public FeatureTypeInfo getFeatureTypeByName(Name name) { return getResourceByName(name, FeatureTypeInfo.class); } public FeatureTypeInfo getFeatureTypeByName(String name) { return (FeatureTypeInfo) getResourceByName(name, FeatureTypeInfo.class); } public List getFeatureTypes() { return getResources(FeatureTypeInfo.class); } public List getFeatureTypesByNamespace(NamespaceInfo namespace) { return getResourcesByNamespace(namespace, FeatureTypeInfo.class); } public FeatureTypeInfo getFeatureTypeByStore(DataStoreInfo dataStore, String name) { return getFeatureTypeByDataStore(dataStore, name); } public FeatureTypeInfo getFeatureTypeByDataStore(DataStoreInfo dataStore, String name) { return getResourceByStore(dataStore, name, FeatureTypeInfo.class); } public List<FeatureTypeInfo> getFeatureTypesByStore(DataStoreInfo store) { return getFeatureTypesByDataStore(store); } public List<FeatureTypeInfo> getFeatureTypesByDataStore(DataStoreInfo store) { return getResourcesByStore(store, FeatureTypeInfo.class); } public CoverageInfo getCoverage(String id) { return (CoverageInfo) getResource(id, CoverageInfo.class); } public CoverageInfo getCoverageByName(String ns, String name) { return (CoverageInfo) getResourceByName(ns, name, CoverageInfo.class); } public CoverageInfo getCoverageByName(NamespaceInfo ns, String name) { return (CoverageInfo) getResourceByName(ns, name, CoverageInfo.class); } public CoverageInfo getCoverageByName(Name name) { return getResourceByName(name, CoverageInfo.class); } public CoverageInfo getCoverageByName(String name) { return (CoverageInfo) getResourceByName(name, CoverageInfo.class); } public List getCoverages() { return getResources(CoverageInfo.class); } public List getCoveragesByNamespace(NamespaceInfo namespace) { return getResourcesByNamespace(namespace, CoverageInfo.class); } public List<CoverageInfo> getCoveragesByStore(CoverageStoreInfo store) { return getResourcesByStore(store, CoverageInfo.class); } public CoverageInfo getCoverageByCoverageStore(CoverageStoreInfo coverageStore, String name) { return getResourceByStore(coverageStore, name, CoverageInfo.class); } public List<CoverageInfo> getCoveragesByCoverageStore(CoverageStoreInfo store) { return getResourcesByStore(store, CoverageInfo.class); } // Layer methods public void add(LayerInfo layer) { validate(layer, true); resolve(layer); if (layer.getType() == null) { if (layer.getResource() instanceof FeatureTypeInfo) { layer.setType(LayerInfo.Type.VECTOR); } else if (layer.getResource() instanceof CoverageInfo) { layer.setType(LayerInfo.Type.RASTER); } else { String msg = "Layer type not set and can't be derived from resource"; throw new IllegalArgumentException(msg); } } layers.add(layer); added(layer); } void validate(LayerInfo layer, boolean isNew) { // TODO: bring back when the layer/publishing split is in act // if ( isNull(layer.getName()) ) { // throw new NullPointerException( "Layer name must not be null" ); // } LayerInfo existing = getLayerByName(layer.getName()); if (existing != null && !existing.getId().equals(layer.getId())) { //JD: since layers are not qualified by anything (yet), check // namespace of the resource, if they are different then allow the // layer to be added if (existing.getResource().getNamespace().equals(layer.getName())) { throw new IllegalArgumentException("Layer named '" + layer.getName() + "' already exists."); } } if (layer.getResource() == null) { throw new NullPointerException("Layer resource must not be null"); } //(JD): not sure if default style should be mandatory //if ( layer.getDefaultStyle() == null ){ // throw new NullPointerException( "Layer default style must not be null" ); //} } public void remove(LayerInfo layer) { //ensure no references to the layer for (LayerGroupInfo lg : layerGroups) { 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)); removed(layer); } public void save(LayerInfo layer) { validate(layer, false); saved(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(Name name) { if (name.getNamespaceURI() != null) { NamespaceInfo ns = getNamespaceByURI(name.getNamespaceURI()); if (ns != null) { return getLayerByName(ns.getPrefix() + ":" + name.getLocalPart()); } } return getLayerByName(name.getLocalPart()); } public LayerInfo getLayerByName(String name) { String prefix = null; String resource = null; int colon = name.indexOf(':'); if (colon != -1) { //search by resource name 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); } } } 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 null; } public List<LayerInfo> getLayers(ResourceInfo resource) { List<LayerInfo> matches = new ArrayList<LayerInfo>(); 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<LayerInfo> getLayers(StyleInfo style) { List<LayerInfo> matches = new ArrayList<LayerInfo>(); 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); } // Map methods 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<MapInfo> getMaps() { return ModificationProxy.createList(new ArrayList(maps), MapInfo.class); } public void add(LayerGroupInfo layerGroup) { validate(layerGroup, true); resolve(layerGroup); if (layerGroup.getStyles().isEmpty()) { for (LayerInfo l : layerGroup.getLayers()) { // default style layerGroup.getStyles().add(null); } } layerGroups.add(layerGroup); added(layerGroup); } void validate(LayerGroupInfo layerGroup, boolean isNew) { if (isNull(layerGroup.getName())) { throw new NullPointerException("Layer group name must not be null"); } LayerGroupInfo existing = getLayerGroupByName(layerGroup.getName()); if (existing != null && !existing.getId().equals(layerGroup.getId())) { throw new IllegalArgumentException("Layer group named '" + layerGroup.getName() + "' already exists."); } if (!isNew) { if (layerGroup.getLayers() == null || layerGroup.getLayers().isEmpty()) { throw new NullPointerException("Layer group must not be empty"); } } if (layerGroup.getStyles() != null && !layerGroup.getStyles().isEmpty() && !(layerGroup.getStyles().size() == layerGroup.getLayers().size())) { throw new IllegalArgumentException("Layer group has different number of styles than layers"); } } public void remove(LayerGroupInfo layerGroup) { layerGroups.remove(unwrap(layerGroup)); removed(layerGroup); } public void save(LayerGroupInfo layerGroup) { validate(layerGroup, false); saved(layerGroup); } public List<LayerGroupInfo> 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; } public void add(MapInfo map) { resolve(map); maps.add(map); added(map); } public void remove(MapInfo map) { maps.remove(unwrap(map)); removed(map); } public void save(MapInfo map) { saved(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; } 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<NamespaceInfo> ns = new ArrayList<NamespaceInfo>(); for (Map.Entry<String, NamespaceInfo> e : namespaces.entrySet()) { if (e.getKey() == null) continue; ns.add(e.getValue()); } return ModificationProxy.createList(ns, NamespaceInfo.class); } public void add(NamespaceInfo namespace) { validate(namespace, true); resolve(namespace); synchronized (namespaces) { namespaces.put(namespace.getPrefix(), namespace); if (namespaces.get(null) == null) { namespaces.put(null, namespace); //fire the event fireModified(this, Arrays.asList("defaultNamespace"), Collections.singletonList(null), Arrays.asList(namespace)); } } added(namespace); } void validate(NamespaceInfo namespace, boolean isNew) { if (isNull(namespace.getPrefix())) { throw new NullPointerException("Namespace prefix must not be null"); } NamespaceInfo existing = getNamespaceByPrefix(namespace.getPrefix()); if (existing != null && !existing.getId().equals(namespace.getId())) { throw new IllegalArgumentException( "Namespace with prefix '" + namespace.getPrefix() + "' already exists."); } if (isNull(namespace.getURI())) { throw new NullPointerException("Namespace uri must not be null"); } try { new URI(namespace.getURI()); } catch (Exception e) { throw new IllegalArgumentException("Invalid URI syntax for '" + namespace.getURI() + "' in namespace '" + namespace.getPrefix() + "'"); } } public void remove(NamespaceInfo namespace) { if (!getResourcesByNamespace(namespace, ResourceInfo.class).isEmpty()) { throw new IllegalArgumentException("Unable to delete non-empty namespace."); } NamespaceInfo defaultNamespace = getDefaultNamespace(); if (namespace.equals(defaultNamespace)) { namespaces.remove(null); } namespaces.remove(namespace.getPrefix()); 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); } } saved(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()); if (ns == null) { throw new IllegalArgumentException("No such namespace: '" + defaultNamespace.getPrefix() + "'"); } NamespaceInfo old = namespaces.get(null); namespaces.put(null, ns); //fire change event fireModified(this, Arrays.asList("defaultNamespace"), Arrays.asList(old), Arrays.asList(defaultNamespace)); } // Workspace methods public void add(WorkspaceInfo workspace) { validate(workspace, true); if (workspaces.containsKey(workspace.getName())) { throw new IllegalArgumentException("Workspace with name '" + workspace.getName() + "' already exists."); } resolve(workspace); synchronized (workspaces) { workspaces.put(workspace.getName(), workspace); // if there is no default workspace use this one as the default if (workspaces.get(null) == null) { workspaces.put(null, workspace); //fire the event fireModified(this, Arrays.asList("defaultWorkspace"), Collections.singletonList(null), Arrays.asList(workspace)); } } added(workspace); } void validate(WorkspaceInfo workspace, boolean isNew) { if (isNull(workspace.getName())) { throw new NullPointerException("workspace name must not be null"); } WorkspaceInfo existing = getWorkspaceByName(workspace.getName()); if (existing != null && !existing.getId().equals(workspace.getId())) { throw new IllegalArgumentException("Workspace named '" + workspace.getName() + "' already exists."); } } public void remove(WorkspaceInfo workspace) { //JD: maintain the link between namespace and workspace, remove this when this is no // longer necessary if (getNamespaceByPrefix(workspace.getName()) != null) { throw new IllegalArgumentException("Cannot delete workspace with linked namespace"); } 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); //default removed, choose another workspace to become default if (!workspaces.isEmpty()) { setDefaultWorkspace(workspaces.values().iterator().next()); } } 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); } } saved(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); workspaces.put(null, workspace); //fire change event fireModified(this, Arrays.asList("defaultWorkspace"), Arrays.asList(old), Arrays.asList(workspace)); } public List<WorkspaceInfo> getWorkspaces() { ArrayList<WorkspaceInfo> ws = new ArrayList<WorkspaceInfo>(); //strip out default namespace for (Map.Entry<String, WorkspaceInfo> e : workspaces.entrySet()) { if (e.getKey() == null) { 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; } // 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; } 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); } public void add(StyleInfo style) { validate(style, true); resolve(style); styles.add(style); added(style); } void validate(StyleInfo style, boolean isNew) { if (isNull(style.getName())) { throw new NullPointerException("Style name must not be null"); } if (isNull(style.getFilename())) { throw new NullPointerException("Style fileName must not be null"); } StyleInfo existing = getStyleByName(style.getName()); if (existing != null && !existing.getId().equals(style.getId())) { throw new IllegalArgumentException("Style named '" + style.getName() + "' already exists."); } } public void remove(StyleInfo style) { //ensure no references to the style for (LayerInfo l : layers) { if (style.equals(l.getDefaultStyle()) || l.getStyles().contains(style)) { throw new IllegalArgumentException("Unable to delete style referenced by '" + l.getName() + "'"); } } styles.remove(unwrap(style)); removed(style); } public void save(StyleInfo style) { validate(style, false); saved(style); } // Event methods public Collection getListeners() { return Collections.unmodifiableCollection(listeners); } public void addListener(CatalogListener listener) { listeners.add(listener); } public void removeListener(CatalogListener listener) { listeners.remove(listener); } public Iterator search(String cql) { // TODO Auto-generated method stub return null; } public ResourcePool getResourcePool() { return resourcePool; } public void setResourcePool(ResourcePool resourcePool) { this.resourcePool = resourcePool; } public GeoServerResourceLoader getResourceLoader() { return resourceLoader; } public void setResourceLoader(GeoServerResourceLoader resourceLoader) { this.resourceLoader = resourceLoader; } public void dispose() { if (stores != null) stores.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(); 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) { 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, List newValues) { CatalogModifyEventImpl event = new CatalogModifyEventImpl(); event.setSource(object); event.setPropertyNames(propertyNames); event.setOldValues(oldValues); event.setNewValues(newValues); event(event); } protected void firePostModified(CatalogInfo object) { CatalogPostModifyEventImpl event = new CatalogPostModifyEventImpl(); event.setSource(object); event(event); } protected void removed(CatalogInfo object) { CatalogRemoveEventImpl event = new CatalogRemoveEventImpl(); event.setSource(object); event(event); } protected void event(CatalogEvent event) { CatalogException toThrow = null; for (Iterator l = listeners.iterator(); l.hasNext();) { try { CatalogListener listener = (CatalogListener) l.next(); if (event instanceof CatalogAddEvent) { listener.handleAddEvent((CatalogAddEvent) event); } else if (event instanceof CatalogRemoveEvent) { listener.handleRemoveEvent((CatalogRemoveEvent) event); } else if (event instanceof CatalogModifyEvent) { listener.handleModifyEvent((CatalogModifyEvent) event); } else if (event instanceof CatalogPostModifyEvent) { listener.handlePostModifyEvent((CatalogPostModifyEvent) event); } } catch (Throwable t) { if (t instanceof CatalogException && toThrow == null) { toThrow = (CatalogException) t; } else { LOGGER.log(Level.WARNING, "Catalog listener threw exception handling event.", t); } } } if (toThrow != null) { throw toThrow; } } /** * 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<String, WorkspaceInfo>(); } for (WorkspaceInfo ws : workspaces.values()) { resolve(ws); } //namespaces if (namespaces == null) { namespaces = new HashMap<String, NamespaceInfo>(); } 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<StyleInfo>(); } 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<LayerInfo>(); } for (LayerInfo l : layers) { resolve(l); } //layer groups if (layerGroups == null) { layerGroups = new ArrayList<LayerGroupInfo>(); } for (LayerGroupInfo lg : layerGroups) { resolve(lg); } //maps if (maps == null) { maps = new ArrayList<MapInfo>(); } for (MapInfo m : maps) { resolve(m); } if (listeners == null) { listeners = new ArrayList<CatalogListener>(); } if (resourcePool == null) { resourcePool = new ResourcePool(this); } } protected void resolve(WorkspaceInfo workspace) { setId(workspace); resolveCollections(workspace); } protected void resolve(NamespaceInfo namespace) { setId(namespace); resolveCollections(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); s.setCatalog(this); } protected void resolve(ResourceInfo resource) { setId(resource); ResourceInfoImpl r = (ResourceInfoImpl) resource; //resolve the store StoreInfo resolved = ResolvingProxy.resolve(this, r.getStore()); if (resolved != null) { r.setStore(resolved); } if (resource instanceof FeatureTypeInfo) { resolve((FeatureTypeInfo) resource); } if (r instanceof CoverageInfo) { resolve((CoverageInfo) resource); } r.setCatalog(this); } private void resolve(CoverageInfo r) { CoverageInfoImpl c = (CoverageInfoImpl) r; if (c.getDimensions() == null) { c.setDimensions(new ArrayList<CoverageDimensionInfo>()); } else { for (CoverageDimensionInfo dim : c.getDimensions()) { if (dim.getNullValues() == null) ((CoverageDimensionImpl) dim).setNullValues(new ArrayList<Double>()); } } resolveCollections(r); } /** * We don't want the world to be able and call this without * going trough {@link #resolve(ResourceInfo)} * @param featureType */ private void resolve(FeatureTypeInfo featureType) { FeatureTypeInfoImpl ft = (FeatureTypeInfoImpl) featureType; resolveCollections(ft); } protected void resolve(LayerInfo layer) { setId(layer); if (layer.getAttribution() == null) { layer.setAttribution(getFactory().createAttribution()); } resolveCollections(layer); } protected void resolve(LayerGroupInfo layerGroup) { setId(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); } } } protected void resolve(StyleInfo style) { setId(style); ((StyleInfoImpl) style).setCatalog(this); } protected void resolve(MapInfo map) { setId(map); } /** * Method which reflectively sets all collections when they are null. */ protected void resolveCollections(Object object) { ClassProperties properties = OwsUtils.getClassProperties(object.getClass()); for (String property : properties.properties()) { Method g = properties.getter(property, null); if (g == null) { continue; } Class type = g.getReturnType(); //only continue if this is a collection or a map if (!(Map.class.isAssignableFrom(type) || Collection.class.isAssignableFrom(type))) { continue; } //only continue if there is also a setter as well Method s = properties.setter(property, null); if (s == null) { continue; } //if the getter returns null, call the setter try { Object value = g.invoke(object, null); if (value == null) { if (Map.class.isAssignableFrom(type)) { if (MetadataMap.class.isAssignableFrom(type)) { value = new MetadataMap(); } else { value = new HashMap(); } } else if (List.class.isAssignableFrom(type)) { value = new ArrayList(); } else if (Set.class.isAssignableFrom(type)) { value = new HashSet(); } else { throw new RuntimeException("Unknown collection type:" + type.getName()); } //initialize s.invoke(object, value); } } catch (Exception e) { throw new RuntimeException(e); } } } 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()); } public void sync(CatalogImpl other) { stores = other.stores; resources = other.resources; namespaces = other.namespaces; workspaces = other.workspaces; layers = other.layers; maps = other.maps; layerGroups = other.layerGroups; styles = other.styles; listeners = other.listeners; if (resourcePool != other.resourcePool) { resourcePool.dispose(); resourcePool = other.resourcePool; } resourceLoader = other.resourceLoader; } public static <T> T unwrap(T obj) { return ModificationProxy.unwrap(obj); } public void accept(CatalogVisitor visitor) { visitor.visit(this); } }