/* (c) 2014 - 2015 Open Source Geospatial Foundation - all rights reserved * (c) 2001 - 2013 OpenPlans * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.config.util; import java.io.BufferedInputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.HashMap; import org.geoserver.catalog.MetadataMap; import org.geoserver.config.GeoServer; import org.geoserver.config.ServiceInfo; import org.geoserver.config.ServiceLoader; import org.geoserver.config.impl.ServiceInfoImpl; import org.geoserver.platform.GeoServerResourceLoader; import org.geoserver.platform.resource.Resource; import org.geoserver.platform.resource.Resources; /** * Service loader which loads and saves a service configuration with xstream. * * @author Justin Deoliveira, The Open Planning Project * */ public abstract class XStreamServiceLoader<T extends ServiceInfo> implements ServiceLoader<T> { GeoServerResourceLoader resourceLoader; String filenameBase; XStreamPersisterFactory xpf = new XStreamPersisterFactory(); public XStreamServiceLoader(GeoServerResourceLoader resourceLoader, String filenameBase) { this.resourceLoader = resourceLoader; this.filenameBase = filenameBase; } public String getFilename() { return filenameBase + ".xml"; } public void setXStreamPeristerFactory(XStreamPersisterFactory xpf) { this.xpf = xpf; } public final T load(GeoServer gs) throws Exception { return load(gs, resourceLoader.get("")); } public final T load(GeoServer gs, Resource directory) throws Exception { //look for file matching classname Resource file; if ( Resources.exists(file = directory.get(getFilename()))) { //xstream it in try (BufferedInputStream in = new BufferedInputStream(file.in())) { XStreamPersister xp = xpf.createXMLPersister(); initXStreamPersister(xp, gs); return initialize( xp.load( in, getServiceClass() ) ); } } else { //create an 'empty' object ServiceInfo service = createServiceFromScratch( gs ); return initialize( (T) service ); } } /** * Fills in all the bits that are normally not loaded automatically by XStream, such * as empty collections * * @param info */ public void initializeService(ServiceInfo info) { initialize((T) info); } /** * Fills in the blanks of the service object loaded by XStream. This implementation makes sure * all collections in {@link ServiceInfoImpl} are initialized, subclasses should override to add * more specific initializations (such as the actual supported versions and so on) * * @param service * */ protected T initialize(T service) { if (service instanceof ServiceInfoImpl) { // initialize all collections to ServiceInfoImpl impl = (ServiceInfoImpl) service; if (impl.getClientProperties() == null) { impl.setClientProperties(new HashMap()); } if (impl.getExceptionFormats() == null) { impl.setExceptionFormats(new ArrayList()); } if (impl.getKeywords() == null) { impl.setKeywords(new ArrayList()); } if (impl.getMetadata() == null) { impl.setMetadata(new MetadataMap()); } if (impl.getVersions() == null) { impl.setVersions(new ArrayList()); } } return service; } public final void save(T service, GeoServer gs) throws Exception { } public final void save(T service, GeoServer gs, Resource directory) throws Exception { String filename = getFilename(); Resource resource = directory == null ? resourceLoader.get(filename) : directory.get(filename); // using resource output stream makes sure we write on a temp file and them move try (OutputStream out = resource.out()) { XStreamPersister xp = xpf.createXMLPersister(); initXStreamPersister(xp, gs); xp.save( service, out ); } } /** * Hook for subclasses to configure the xstream. * <p> * The most common use is to do some aliasing or omit some fields. * </p> */ protected void initXStreamPersister( XStreamPersister xp, GeoServer gs ) { xp.setGeoServer( gs ); xp.setCatalog( gs.getCatalog() ); xp.getXStream().alias( filenameBase, getServiceClass() ); } public final T create(GeoServer gs) { return createServiceFromScratch(gs); } protected abstract T createServiceFromScratch(GeoServer gs); }