/* (c) 2014 Open Source Geospatial Foundation - all rights reserved * (c) 2014 Boundless * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.cluster.hazelcast; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.annotation.Nullable; import org.geoserver.catalog.Catalog; import org.geoserver.catalog.CatalogInfo; import org.geoserver.catalog.CatalogVisitor; import org.geoserver.catalog.CoverageInfo; import org.geoserver.catalog.CoverageStoreInfo; import org.geoserver.catalog.DataStoreInfo; import org.geoserver.catalog.FeatureTypeInfo; import org.geoserver.catalog.Info; import org.geoserver.catalog.LayerGroupInfo; import org.geoserver.catalog.LayerInfo; import org.geoserver.catalog.NamespaceInfo; import org.geoserver.catalog.ResourcePool; import org.geoserver.catalog.StyleInfo; import org.geoserver.catalog.WMSLayerInfo; import org.geoserver.catalog.WMSStoreInfo; import org.geoserver.catalog.WorkspaceInfo; import org.geoserver.platform.GeoServerExtensions; import org.geotools.data.DataStore; /** * Proxy for {@link CatalogInfo} concrete interfaces used to notify the local cluster member of * objects removed on another member. * <p> * The only methods proxied are {@link CatalogInfo#getId() getId()}, {@code getName()} for the ones * that have such a method, and {@link CatalogInfo#accept(CatalogVisitor)}. * <p> * {@code accept(CatalogVisitor)} is crucial for the {@link ResourcePool} catalog listener to be * able of disposing locally cached resources such as {@link DataStore} instances. * */ class RemovedObjectProxy implements InvocationHandler { private final String id; private final String name; private final Class<? extends Info> infoInterface; private final Map<String, CatalogInfo> catalogCollaborators; private String nativeName; public RemovedObjectProxy(String id, String name, Class<? extends Info> infoInterface) { this(id, name, infoInterface, null); } public RemovedObjectProxy(String id, String name, Class<? extends Info> infoInterface, @Nullable String nativeName) { checkNotNull(id, "id"); checkNotNull(name, "name"); checkNotNull(infoInterface, "infoInterface"); checkArgument(infoInterface.isInterface(), "%s is not an interface", infoInterface); this.id = id; this.name = name; this.infoInterface = infoInterface; this.nativeName = nativeName; this.catalogCollaborators = new HashMap<String, CatalogInfo>(); } /** * Makes the proxy return a catalog object * @param property * @param id */ public void addCatalogCollaborator(String property, CatalogInfo info) { String accessor = "get" + property.substring(0, 1).toUpperCase() + property.substring(1); catalogCollaborators.put(accessor, info); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if ("getid".equalsIgnoreCase(method.getName())) { return id; } if ("getname".equalsIgnoreCase(method.getName())) { return name; } if ("getNativeName".equalsIgnoreCase(method.getName())) { return nativeName; } if ("accept".equals(method.getName())) { proxyVisitory(proxy, method, (CatalogVisitor) args[0]); } if (catalogCollaborators.containsKey(method.getName())) { return catalogCollaborators.get(method.getName()); } Class<?> returnType = method.getReturnType(); if (List.class.isAssignableFrom(returnType)) { return Collections.EMPTY_LIST; } return null; } // void accept( CatalogVisitor visitor ); private void proxyVisitory(Object proxy, Method method, CatalogVisitor catalogVisitor) { if (NamespaceInfo.class.equals(infoInterface)) { catalogVisitor.visit((NamespaceInfo) proxy); } else if (WorkspaceInfo.class.equals(infoInterface)) { catalogVisitor.visit((WorkspaceInfo) proxy); } else if (CoverageInfo.class.equals(infoInterface)) { catalogVisitor.visit((CoverageInfo) proxy); } else if (FeatureTypeInfo.class.equals(infoInterface)) { catalogVisitor.visit((FeatureTypeInfo) proxy); } else if (WMSLayerInfo.class.equals(infoInterface)) { catalogVisitor.visit((WMSLayerInfo) proxy); } else if (CoverageStoreInfo.class.equals(infoInterface)) { catalogVisitor.visit((CoverageStoreInfo) proxy); } else if (DataStoreInfo.class.equals(infoInterface)) { catalogVisitor.visit((DataStoreInfo) proxy); } else if (WMSStoreInfo.class.equals(infoInterface)) { catalogVisitor.visit((WMSStoreInfo) proxy); } else if (StyleInfo.class.equals(infoInterface)) { catalogVisitor.visit((StyleInfo) proxy); } else if (LayerInfo.class.equals(infoInterface)) { catalogVisitor.visit((LayerInfo) proxy); } else if (LayerGroupInfo.class.equals(infoInterface)) { catalogVisitor.visit((LayerGroupInfo) proxy); } else if (Catalog.class.equals(infoInterface)) { catalogVisitor.visit((Catalog) proxy); } } @Override public String toString() { return "RemovedObjectProxy[(" + infoInterface.getSimpleName() + "[id=" + id + ", name=" + name + "]]"; } @Override protected Object clone() throws CloneNotSupportedException { // TODO Auto-generated method stub return super.clone(); } }