/* Copyright (c) 2011 GeoSolutions - http://www.geo-solutions.it/. All rights reserved. * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package it.geosolutions.geoserver.jms.impl.handlers.catalog; import it.geosolutions.geoserver.jms.events.ToggleSwitch; import it.geosolutions.geoserver.jms.impl.utils.BeanUtils; import java.lang.reflect.InvocationTargetException; import java.util.List; import org.geoserver.catalog.Catalog; import org.geoserver.catalog.CatalogException; import org.geoserver.catalog.CatalogInfo; 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.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.WMSStoreInfo; import org.geoserver.catalog.WorkspaceInfo; import org.geoserver.catalog.event.CatalogEvent; import org.geoserver.catalog.event.CatalogModifyEvent; import com.thoughtworks.xstream.XStream; /** * * Handle modify events synchronizing catalog with serialized objects * * @author Carlo Cancellieri - carlo.cancellieri@geo-solutions.it * */ public class JMSCatalogModifyEventHandler extends JMSCatalogEventHandler { private final Catalog catalog; private final ToggleSwitch producer; /** * * @param catalog * @param xstream * @param clazz * @param producer */ public JMSCatalogModifyEventHandler(Catalog catalog, XStream xstream, Class clazz, ToggleSwitch producer) { super(xstream, clazz); this.catalog = catalog; this.producer = producer; } @Override public boolean synchronize(CatalogEvent event) throws Exception { if (event == null) { throw new IllegalArgumentException("Incoming object is null"); } try { if (event instanceof CatalogModifyEvent) { final CatalogModifyEvent modifyEv = ((CatalogModifyEvent) event); producer.disable(); JMSCatalogModifyEventHandler.modify(catalog, modifyEv); } else { // incoming object not recognized if (LOGGER.isLoggable(java.util.logging.Level.SEVERE)) LOGGER.severe("Unrecognized event type"); return false; } } catch (Exception e) { if (LOGGER.isLoggable(java.util.logging.Level.SEVERE)) LOGGER.severe(this.getClass()+" is unable to synchronize the incoming event: "+event); throw e; } finally { // re enable the producer producer.enable(); } return true; } /** * simulate a catalog.save() rebuilding the EventModify proxy object locally * {@link * org.geoserver.catalog.impl.DefaultCatalogFacade.saved(CatalogInfo)} * * @param catalog * @param modifyEv * @throws IllegalAccessException * @throws InvocationTargetException * @throws NoSuchMethodException * * TODO synchronization on catalog object */ protected static void modify(final Catalog catalog, CatalogModifyEvent modifyEv) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { final CatalogInfo info = modifyEv.getSource(); // check if name is changed String name = getOldName(catalog, modifyEv); if (info instanceof LayerGroupInfo) { // check if name is changed if (name == null) { // name is unchanged name = ((LayerGroupInfo) info).getName(); } final LayerGroupInfo localObject = catalog .getLayerGroupByName(name); if (localObject == null) { throw new CatalogException("Unable to locate " + info + " named: " + name + " locally."); } BeanUtils.smartUpdate(localObject, modifyEv.getPropertyNames(), modifyEv.getNewValues()); catalog.save(localObject); } else if (info instanceof LayerInfo) { // check if name is changed if (name == null) { // name is unchanged name = ((LayerInfo) info).getName(); } final LayerInfo localObject = catalog.getLayerByName(name); if (localObject == null) { throw new CatalogException("Unable to locate " + info + " named: " + name + " locally."); } BeanUtils.smartUpdate(localObject, modifyEv.getPropertyNames(), modifyEv.getNewValues()); catalog.save(localObject); } else if (info instanceof MapInfo) { // check if name is changed if (name == null) { // name is unchanged name = ((MapInfo) info).getName(); } final MapInfo localObject = catalog.getMapByName(name); if (localObject == null) { throw new CatalogException("Unable to locate " + info + " named: " + name + " locally."); } BeanUtils.smartUpdate(localObject, modifyEv.getPropertyNames(), modifyEv.getNewValues()); catalog.save(localObject); } else if (info instanceof NamespaceInfo) { final String uri; final Object uriObj = getOldValue(catalog, modifyEv, "uRI"); if (uriObj != null) { uri = uriObj.toString(); } else { // uri is unchanged uri = ((NamespaceInfo) info).getURI(); } final NamespaceInfo localObject = catalog.getNamespaceByURI(uri); if (localObject == null) { throw new CatalogException("Unable to locate " + info + " uri: " + uri + " locally."); } BeanUtils.smartUpdate(localObject, modifyEv.getPropertyNames(), modifyEv.getNewValues()); catalog.save(localObject); } else if (info instanceof StoreInfo) { // check if name is changed if (name == null) { // name is unchanged name = ((StoreInfo) info).getName(); } // check if workspace is changed final WorkspaceInfo workspace; final Object objWorkpsace = getOldValue(catalog, modifyEv, "workspace"); if (objWorkpsace != null) { workspace = (WorkspaceInfo) objWorkpsace; } else { // workspace is unchanged workspace = ((StoreInfo) info).getWorkspace(); } final StoreInfo localObject; if (info instanceof CoverageStoreInfo) { localObject = catalog.getStoreByName(workspace, name, CoverageStoreInfo.class); } else if (info instanceof DataStoreInfo) { localObject = catalog.getStoreByName(workspace, name, DataStoreInfo.class); } else if (info instanceof WMSStoreInfo) { localObject = catalog.getStoreByName(workspace, name, WMSStoreInfo.class); } else { throw new IllegalArgumentException( "Unable to provide localization for the passed instance"); } if (localObject == null) { throw new CatalogException("Unable to locate " + info + " named: " + name + " locally."); } BeanUtils.smartUpdate(localObject, modifyEv.getPropertyNames(), modifyEv.getNewValues()); catalog.save(localObject); } else if (info instanceof ResourceInfo) { // check if name is changed if (name == null) { // name is unchanged name = ((ResourceInfo) info).getName(); } // check if namespace is changed final NamespaceInfo namespace; final Object objWorkpsace = getOldValue(catalog, modifyEv, "namespace"); if (objWorkpsace != null) { namespace = (NamespaceInfo) objWorkpsace; } else { // workspace is unchanged namespace = ((ResourceInfo) info).getNamespace(); } final ResourceInfo localObject; if (info instanceof CoverageInfo) { // coverage localObject = catalog.getCoverageByName(namespace, name); } else if (info instanceof FeatureTypeInfo) { // feature localObject = catalog.getFeatureTypeByName(namespace, name); } else if (info instanceof WMSLayerInfo) { // wmslayer localObject = catalog.getResourceByName(namespace, name, WMSLayerInfo.class); } else { throw new IllegalArgumentException( "Unable to provide localization for the passed instance"); } if (localObject == null) { throw new CatalogException("Unable to locate " + info + " named: " + name + " locally."); } BeanUtils.smartUpdate(localObject, modifyEv.getPropertyNames(), modifyEv.getNewValues()); catalog.save(localObject); } else if (info instanceof StyleInfo) { // check if name is changed if (name == null) { // name is unchanged name = ((StyleInfo) info).getName(); } final StyleInfo localObject = catalog.getStyleByName(name); if (localObject == null) { throw new CatalogException("Unable to locate " + info + " named: " + name + " locally."); } BeanUtils.smartUpdate(localObject, modifyEv.getPropertyNames(), modifyEv.getNewValues()); catalog.save(localObject); } else if (info instanceof WorkspaceInfo) { // check if name is changed if (name == null) { // name is unchanged name = ((WorkspaceInfo) info).getName(); } final WorkspaceInfo localObject = catalog.getWorkspaceByName(name); if (localObject == null) { throw new CatalogException("Unable to locate " + info + " named: " + name + " locally."); } BeanUtils.smartUpdate(localObject, modifyEv.getPropertyNames(), modifyEv.getNewValues()); catalog.save(localObject); } else if (info instanceof CatalogInfo) { // change default workspace in the handled catalog /** * This piece of code was extracted from: {@link * org.geoserver.catalog.NamespaceWorkspaceConsistencyListener. * handleModifyEvent(CatalogModifyEvent)} */ final List<String> properties = modifyEv.getPropertyNames(); if (properties.contains("defaultNamespace")) { final NamespaceInfo newDefault = (NamespaceInfo) modifyEv .getNewValues().get( properties.indexOf("defaultNamespace")); if (newDefault != null) { final WorkspaceInfo ws = catalog .getWorkspaceByName(newDefault.getPrefix()); if (ws != null && !catalog.getDefaultWorkspace().equals(ws)) { catalog.setDefaultWorkspace(ws); } } } else if (properties.contains("defaultWorkspace")) { final WorkspaceInfo newDefault = (WorkspaceInfo) modifyEv .getNewValues().get( properties.indexOf("defaultWorkspace")); if (newDefault != null) { final NamespaceInfo ns = catalog .getNamespaceByPrefix(newDefault.getName()); if (ns != null && !catalog.getDefaultNamespace().equals(ns)) { catalog.setDefaultNamespace(ns); } } } } else { if (LOGGER.isLoggable(java.util.logging.Level.WARNING)) { LOGGER.warning("info - ID: " + info.getId() + " toString: " + info.toString()); } throw new IllegalArgumentException("Bad incoming object: " + info.toString()); } } /** * get the local old name for the passed CatalogInfo event * * @param catalog * the catalog * @param ev * the modify event * @return a String representing the old name or null if name is not changed * or not exists at all */ private static String getOldName(final Catalog catalog, final CatalogModifyEvent ev) { // try to get the old value for the name final Object name = getOldValue(catalog, ev, "name"); // check return and return a string representation of the name or null return name != null ? name.toString() : null; } /** * get the old property for the passed CatalogInfo event * * @param catalog * the catalog * @param ev * the modify event * @param oldProp * the name of the old property to search for * @return an Object representing the old value of the passed property or * null if name is not changed or not exists at all */ private static Object getOldValue(final Catalog catalog, final CatalogModifyEvent ev, final String oldProp) { final CatalogInfo service = ev.getSource(); if (service == null) { throw new IllegalArgumentException("passed service is null"); } // check if name is changed final List<String> props = ev.getPropertyNames(); final int index = props.indexOf(oldProp); if (index != -1) { final List<Object> oldValues = ev.getOldValues(); // search the Service using the old name return oldValues.get(index); } else { return null; } } }