/* (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;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import org.geoserver.catalog.Catalog;
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.NamespaceInfo;
import org.geoserver.catalog.ResourceInfo;
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.catalog.Wrapper;
import org.geoserver.catalog.event.CatalogListener;
import org.geoserver.catalog.impl.CatalogImpl;
import org.geoserver.catalog.util.LegacyCatalogImporter;
import org.geoserver.catalog.util.LegacyCatalogReader;
import org.geoserver.catalog.util.LegacyFeatureTypeInfoReader;
import org.geoserver.config.AsynchResourceIterator.ResourceMapper;
import org.geoserver.config.util.LegacyConfigurationImporter;
import org.geoserver.config.util.XStreamPersister;
import org.geoserver.config.util.XStreamPersisterFactory;
import org.geoserver.config.util.XStreamServiceLoader;
import org.geoserver.platform.GeoServerExtensions;
import org.geoserver.platform.GeoServerResourceLoader;
import org.geoserver.platform.resource.Paths;
import org.geoserver.platform.resource.Resource;
import org.geoserver.platform.resource.Resource.Type;
import org.geoserver.platform.resource.Resources;
import org.geoserver.platform.resource.Resources.ExtensionFilter;
import org.geoserver.util.Filter;
import org.geoserver.util.IOUtils;
import org.geotools.util.logging.Logging;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
/**
* Initializes GeoServer configuration and catalog on startup.
* <p>
* This class post processes the singleton beans {@link Catalog} and {@link GeoServer}, populating
* them from stored configuration.
* </p>
* @author Justin Deoliveira, The Open Planning Project
*
*/
public abstract class GeoServerLoader {
static Logger LOGGER = Logging.getLogger( "org.geoserver" );
/**
* Workspace IO resources
*/
static final class WorkspaceContents {
Resource resource;
byte[] contents;
byte[] nsContents;
public WorkspaceContents(Resource resource, byte[] contents, byte[] nsContents) {
this.resource = resource;
this.contents = contents;
this.nsContents = nsContents;
}
}
/**
* {@link ResourceMapper} for workspaces
*/
static final class WorkspaceMapper implements ResourceMapper<WorkspaceContents> {
@Override
public WorkspaceContents apply(Resource rd) throws IOException {
Resource wr = rd.get("workspace.xml");
Resource nr = rd.get("namespace.xml");
if (Resources.exists(wr) && Resources.exists(nr)) {
byte[] contents = wr.getContents();
byte[] nrContents = nr.getContents();
return new WorkspaceContents(rd, contents, nrContents);
} else {
LOGGER.warning("Ignoring workspace directory " + rd.path());
return null;
}
}
}
/**
* Data store IO resources
*/
static final class StoreContents {
Resource resource;
byte[] contents;
public StoreContents(Resource resource, byte[] contents) {
super();
this.resource = resource;
this.contents = contents;
}
}
/**
* Layer IO resources
*/
static final class LayerContents {
Resource resource;
byte[] contents;
byte[] layerContents;
public LayerContents(Resource resource, byte[] contents, byte[] layerContents) {
this.resource = resource;
this.contents = contents;
this.layerContents = layerContents;
}
}
/**
* Resource/Layer mapper to IO resources (generic)
*/
static final class ResourceLayerMapper implements ResourceMapper<LayerContents> {
private String resourceFileName;
private String resourceType;
public ResourceLayerMapper(String resourceFileName, String resourceType) {
this.resourceFileName = resourceFileName;
this.resourceType = resourceType;
}
@Override
public LayerContents apply(Resource rd) throws IOException {
Resource r = rd.get(resourceFileName);
Resource lr = rd.get("layer.xml");
if (Resources.exists(r) && Resources.exists(lr)) {
byte[] contents = r.getContents();
byte[] lrContents = lr.getContents();
return new LayerContents(rd, contents, lrContents);
} else {
LOGGER.warning("Ignoring " + resourceType + " directory " + rd.path());
return null;
}
}
}
/** Feature Type IO resource mapper */
static final ResourceLayerMapper FEATURE_LAYER_MAPPER = new ResourceLayerMapper("featuretype.xml", "feature type");
/** Coverage IO resource mapper */
static final ResourceLayerMapper COVERAGE_LAYER_MAPPER = new ResourceLayerMapper("coverage.xml", "coverage");
/** WMS Layer IO resource mapper */
static final ResourceLayerMapper WMS_LAYER_MAPPER = new ResourceLayerMapper("wmslayer.xml", "wms layer");
/**
* Generic layer catalog loader for all types of IO resources
*
* @author Andrea Aime - GeoSolutions
*/
static final class LayerLoader<T extends ResourceInfo> implements Consumer<LayerContents> {
Class<T> clazz;
XStreamPersister xp;
Catalog catalog;
public LayerLoader(Class<T> clazz, XStreamPersister xp, Catalog catalog) {
this.clazz = clazz;
this.xp = xp;
this.catalog = catalog;
}
@Override
public void accept(LayerContents lc) {
T ft = null;
try {
ft = depersist(xp, lc.contents,clazz);
catalog.add(ft);
} catch( Exception e ) {
LOGGER.log( Level.WARNING, "Failed to load feature type", e);
return;
}
if(LOGGER.isLoggable(Level.INFO)) {
LOGGER.info( "Loaded feature type '" + lc.resource.name() +"'");
}
try {
LayerInfo l = depersist(xp, lc.layerContents, LayerInfo.class );
catalog.add( l );
LOGGER.info( "Loaded layer '" + l.getName() + "'" );
} catch( Exception e ) {
LOGGER.log( Level.WARNING, "Failed to load layer " + lc.resource.name(), e);
}
}
}
static final ExtensionFilter XML_FILTER = new Resources.ExtensionFilter("XML");
protected GeoServerResourceLoader resourceLoader;
GeoServer geoserver;
XStreamPersisterFactory xpf = new XStreamPersisterFactory();
//JD: this is a hack for the moment, it is used only to maintain tests since the test setup relies
// on the old data directory structure, once the tests have been ported to the new structure
// this ugly hack can die
static boolean legacy = false;
public GeoServerLoader( GeoServerResourceLoader resourceLoader ) {
this.resourceLoader = resourceLoader;
}
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
}
public void setXStreamPeristerFactory(XStreamPersisterFactory xpf) {
this.xpf = xpf;
}
public static void setLegacy(boolean legacy) {
GeoServerLoader.legacy = legacy;
}
public final Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
return bean;
}
public final Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if ( bean instanceof Catalog ) {
//ensure this is not a wrapper but the real deal
if ( bean instanceof Wrapper && ((Wrapper) bean).isWrapperFor(Catalog.class) ) {
return bean;
}
//load
try {
Catalog catalog = (Catalog) bean;
XStreamPersister xp = xpf.createXMLPersister();
xp.setCatalog( catalog );
loadCatalog( catalog, xp );
//initialize styles
initializeStyles(catalog, xp);
}
catch (Exception e) {
throw new RuntimeException( e );
}
}
if ( bean instanceof GeoServer ) {
geoserver = (GeoServer) bean;
try {
XStreamPersister xp = xpf.createXMLPersister() ;
xp.setCatalog(geoserver.getCatalog());
loadGeoServer(geoserver, xp);
//load initializers
loadInitializers(geoserver);
}
catch (Exception e) {
throw new RuntimeException( e );
}
//initialize();
}
return bean;
}
protected abstract void loadCatalog(Catalog catalog, XStreamPersister xp) throws Exception;
protected abstract void loadGeoServer(final GeoServer geoServer, XStreamPersister xp) throws Exception;
protected void loadInitializers(GeoServer geoServer) throws Exception {
//load initializer extensions
List<GeoServerInitializer> initializers = GeoServerExtensions.extensions( GeoServerInitializer.class );
for ( GeoServerInitializer initer : initializers ) {
try {
initer.initialize( geoServer );
}
catch( Throwable t ) {
LOGGER.log(Level.SEVERE, "Failed to run initializer " + initer, t);
}
}
}
protected void reloadInitializers(GeoServer geoServer) throws Exception {
//reload applicable initializer extensions
List<GeoServerReinitializer> initializers = GeoServerExtensions.extensions( GeoServerReinitializer.class );
for ( GeoServerReinitializer initer : initializers ) {
try {
initer.reinitialize( geoServer );
}
catch( Throwable t ) {
LOGGER.log(Level.SEVERE, "Failed to run initializer " + initer, t);
}
}
}
/**
* Does some post processing on the catalog to ensure that the "well-known" styles
* are always around.
*/
protected void initializeStyles( Catalog catalog, XStreamPersister xp) throws IOException {
if ( catalog.getStyleByName( StyleInfo.DEFAULT_POINT ) == null ) {
initializeStyle( catalog, StyleInfo.DEFAULT_POINT, "default_point.sld" );
}
if ( catalog.getStyleByName( StyleInfo.DEFAULT_LINE ) == null ) {
initializeStyle( catalog, StyleInfo.DEFAULT_LINE, "default_line.sld" );
}
if ( catalog.getStyleByName( StyleInfo.DEFAULT_POLYGON ) == null ) {
initializeStyle( catalog, StyleInfo.DEFAULT_POLYGON, "default_polygon.sld" );
}
if ( catalog.getStyleByName( StyleInfo.DEFAULT_RASTER ) == null ) {
initializeStyle( catalog, StyleInfo.DEFAULT_RASTER, "default_raster.sld" );
}
if (catalog.getStyleByName(StyleInfo.DEFAULT_GENERIC) == null) {
initializeStyle(catalog, StyleInfo.DEFAULT_GENERIC, "default_generic.sld");
}
}
/**
* Copies a well known style out to the data directory and adds a catalog entry for it.
*/
void initializeStyle(Catalog catalog, String styleName, String sld) throws IOException {
// copy the file out to the data directory if necessary
Resource styleResource = resourceLoader.get(Paths.path("styles", sld));
if (!Resources.exists(styleResource)) {
IOUtils.copy(GeoServerLoader.class.getResourceAsStream(sld), styleResource.out());
}
// create a style for it
StyleInfo s = catalog.getFactory().createStyle();
s.setName(styleName);
s.setFilename(sld);
catalog.add(s);
}
public void reload() throws Exception {
destroy();
//reload catalog, make sure we reload the underlying catalog, not any wrappers
Catalog catalog = geoserver.getCatalog();
if ( catalog instanceof Wrapper ) {
catalog = ((Wrapper)geoserver.getCatalog()).unwrap(Catalog.class);
}
XStreamPersister xp = xpf.createXMLPersister();
xp.setCatalog( catalog );
loadCatalog( catalog, xp );
loadGeoServer( geoserver, xp);
reloadInitializers(geoserver);
}
protected void readCatalog(Catalog catalog, XStreamPersister xp) throws Exception {
// we are going to synch up the catalogs and need to preserve listeners,
// but these two fellas are attached to the new catalog as well
catalog.removeListeners(ResourcePool.CacheClearingListener.class);
catalog.removeListeners(GeoServerPersister.class);
List<CatalogListener> listeners = new ArrayList<CatalogListener>(catalog.getListeners());
//look for catalog.xml, if it exists assume we are dealing with
// an old data directory
Resource f = resourceLoader.get( "catalog.xml" );
if ( !Resources.exists(f) ) {
//assume 2.x style data directory
CatalogImpl catalog2 = (CatalogImpl) readCatalog( xp );
// make to remove the old resource pool catalog listener
((CatalogImpl)catalog).sync( catalog2 );
} else {
// import old style catalog, register the persister now so that we start
// with a new version of the catalog
CatalogImpl catalog2 = (CatalogImpl) readLegacyCatalog( f, xp );
((CatalogImpl)catalog).sync( catalog2 );
}
// attach back the old listeners
for (CatalogListener listener : listeners) {
catalog.addListener(listener);
}
}
boolean checkStoresOnStartup(XStreamPersister xp) {
Resource f = resourceLoader.get( "global.xml");
if ( Resources.exists(f) ) {
try {
GeoServerInfo global = depersist(xp, f, GeoServerInfo.class);
final ResourceErrorHandling resourceErrorHandling = global.getResourceErrorHandling();
return resourceErrorHandling != null && !ResourceErrorHandling.SKIP_MISCONFIGURED_LAYERS.equals(
resourceErrorHandling);
} catch (IOException e) {
LOGGER.log(Level.INFO, "Failed to determine the capabilities resource error handling", e);
}
}
return true;
}
/**
* Reads the catalog from disk.
*/
Catalog readCatalog( XStreamPersister xp ) throws Exception {
CatalogImpl catalog = new CatalogImpl();
catalog.setResourceLoader(resourceLoader);
xp.setCatalog( catalog );
xp.setUnwrapNulls(false);
// see if we really need to verify stores on startup
boolean checkStores = checkStoresOnStartup(xp);
if(!checkStores) {
catalog.setExtendedValidation(false);
}
//global styles
loadStyles(resourceLoader.get( "styles" ), catalog, xp);
//workspaces, stores, and resources
Resource workspaces = resourceLoader.get( "workspaces" );
if ( Resources.exists(workspaces) ) {
//do a first quick scan over all workspaces, setting the default
Resource dws = workspaces.get("default.xml");
WorkspaceInfo defaultWorkspace = null;
if (Resources.exists(dws)) {
try {
defaultWorkspace = depersist(xp, dws, WorkspaceInfo.class);
LOGGER.info("Loaded default workspace " + defaultWorkspace.getName());
} catch( Exception e ) {
LOGGER.log(Level.WARNING, "Failed to load default workspace", e);
}
} else {
LOGGER.warning("No default workspace was found.");
}
List<Resource> workspaceList = workspaces.list().parallelStream()
.filter(r -> Resources.DirectoryFilter.INSTANCE.accept(r))
.collect(Collectors.toList());
try (AsynchResourceIterator<WorkspaceContents> it = new AsynchResourceIterator<>(
workspaces, Resources.DirectoryFilter.INSTANCE, new WorkspaceMapper())) {
while (it.hasNext()) {
WorkspaceContents wc = it.next();
WorkspaceInfo ws;
final Resource workspaceResource = wc.resource;
try {
ws = depersist(xp, wc.contents, WorkspaceInfo.class);
catalog.add(ws);
if (LOGGER.isLoggable(Level.INFO)) {
LOGGER.info("Loaded workspace '" + ws.getName() + "'");
}
} catch (Exception e) {
LOGGER.log(Level.WARNING,
"Failed to load workspace '" + workspaceResource.name() + "'", e);
continue;
}
// load the namespace
NamespaceInfo ns = null;
try {
ns = depersist(xp, wc.nsContents, NamespaceInfo.class);
catalog.add(ns);
} catch (Exception e) {
LOGGER.log(Level.WARNING,
"Failed to load namespace for '" + workspaceResource.name() + "'", e);
}
// set the default workspace, this value might be null in the case of coming from a
// 2.0.0 data directory. See https://osgeo-org.atlassian.net/browse/GEOS-3440
if (defaultWorkspace != null) {
if (ws.getName().equals(defaultWorkspace.getName())) {
catalog.setDefaultWorkspace(ws);
if (ns != null) {
catalog.setDefaultNamespace(ns);
}
}
} else {
// create the default.xml file
defaultWorkspace = catalog.getDefaultWorkspace();
if (defaultWorkspace != null) {
try {
persist(xp, defaultWorkspace, dws);
} catch (Exception e) {
LOGGER.log(Level.WARNING, "Failed to persist default workspace '"
+ workspaceResource.name() + "'", e);
}
}
}
//load the styles for the workspace
Resource styles = workspaceResource.get("styles");
if (styles != null) {
loadStyles(styles, catalog, xp);
}
}
}
// maps each store into a StoreContents
ResourceMapper<StoreContents> storeMapper = sd -> {
Resource f = sd.get("datastore.xml");
if(Resources.exists(f)) {
return new StoreContents(f, f.getContents());
}
f = sd.get("coveragestore.xml");
if(Resources.exists(f)) {
return new StoreContents(f, f.getContents());
}
f = sd.get("wmsstore.xml");
if(Resources.exists(f)) {
return new StoreContents(f, f.getContents());
}
if(!isConfigDirectory(sd)) {
LOGGER.warning( "Ignoring store directory '" + sd.name() + "'");
}
// nothing found
return null;
};
for (Resource wsd : workspaceList) {
// load the stores for this workspace
try (AsynchResourceIterator<StoreContents> it = new AsynchResourceIterator<>(wsd,
Resources.DirectoryFilter.INSTANCE, storeMapper)) {
while (it.hasNext()) {
StoreContents storeContents = it.next();
final String resourceName = storeContents.resource.name();
if ("datastore.xml".equals(resourceName)) {
loadDataStore(storeContents, catalog, xp, checkStores);
} else if ("coveragestore.xml".equals(resourceName)) {
loadCoverageStore(storeContents, catalog, xp);
} else if ("wmsstore.xml".equals(resourceName)) {
loadWmsStore(storeContents, catalog, xp);
} else if (!isConfigDirectory(storeContents.resource)) {
LOGGER.warning("Ignoring store directory '"
+ storeContents.resource.name() + "'");
continue;
}
}
}
// load the layer groups for this workspace
Resource layergroups = wsd.get("layergroups");
if (layergroups != null) {
loadLayerGroups(layergroups, catalog, xp);
}
}
}
else {
LOGGER.warning( "No 'workspaces' directory found, unable to load any stores." );
}
//layergroups
Resource layergroups = resourceLoader.get( "layergroups" );
if (layergroups != null) {
loadLayerGroups(layergroups, catalog, xp);
}
xp.setUnwrapNulls(true);
catalog.resolve();
// re-enable extended validation
if(!checkStores) {
catalog.setExtendedValidation(true);
}
return catalog;
}
private void loadWmsStore(StoreContents storeContents, CatalogImpl catalog,
XStreamPersister xp) {
final Resource storeResource = storeContents.resource;
WMSStoreInfo wms = null;
try {
wms = depersist( xp, storeContents.contents, WMSStoreInfo.class );
catalog.add( wms );
LOGGER.info( "Loaded wmsstore '" + wms.getName() +"'");
} catch( Exception e ) {
LOGGER.log( Level.WARNING, "Failed to load wms store '" + storeResource.name() +"'", e);
return;
}
// load wms layers
LayerLoader<WMSLayerInfo> coverageLoader = new LayerLoader<>(WMSLayerInfo.class, xp, catalog);
try(AsynchResourceIterator<LayerContents> it = new AsynchResourceIterator<>(storeResource.parent(), Resources.DirectoryFilter.INSTANCE, WMS_LAYER_MAPPER)) {
while(it.hasNext()) {
LayerContents lc = it.next();
coverageLoader.accept(lc);
}
}
}
private void loadCoverageStore(StoreContents storeContents, CatalogImpl catalog,
XStreamPersister xp) {
CoverageStoreInfo cs = null;
final Resource storeResource = storeContents.resource;
try {
cs = depersist( xp, storeContents.contents, CoverageStoreInfo.class );
catalog.add( cs );
if(LOGGER.isLoggable(Level.INFO)) {
LOGGER.info( "Loaded coverage store '" + cs.getName() +"'");
}
} catch( Exception e ) {
LOGGER.log( Level.WARNING, "Failed to load coverage store '" + storeResource.name() +"'", e);
return;
}
// load coverages
LayerLoader<CoverageInfo> coverageLoader = new LayerLoader<>(CoverageInfo.class, xp,
catalog);
try (AsynchResourceIterator<LayerContents> it = new AsynchResourceIterator<>(
storeResource.parent(), Resources.DirectoryFilter.INSTANCE,
COVERAGE_LAYER_MAPPER)) {
while (it.hasNext()) {
LayerContents lc = it.next();
coverageLoader.accept(lc);
}
}
}
private void loadDataStore(StoreContents storeContents, CatalogImpl catalog, XStreamPersister xp, boolean checkStores) {
final Resource storeResource = storeContents.resource;
DataStoreInfo ds;
try {
ds = depersist( xp, storeContents.contents, DataStoreInfo.class );
catalog.add( ds );
if(LOGGER.isLoggable(Level.INFO)) {
LOGGER.info( "Loaded data store '" + ds.getName() +"'");
}
if (checkStores && ds.isEnabled()) {
//connect to the datastore to determine if we should disable it
try {
ds.getDataStore(null);
} catch( Throwable t ) {
LOGGER.warning( "Error connecting to '" + ds.getName() + "'. Disabling." );
LOGGER.log( Level.INFO, "", t );
ds.setError(t);
ds.setEnabled(false);
}
}
} catch( Exception e ) {
LOGGER.log( Level.WARNING, "Failed to load data store '" + storeResource.parent().name() + "'", e);
return;
}
// load feature types
LayerLoader<FeatureTypeInfo> featureLoader = new LayerLoader<>(FeatureTypeInfo.class, xp, catalog);
try(AsynchResourceIterator<LayerContents> it = new AsynchResourceIterator<>(storeResource.parent(), Resources.DirectoryFilter.INSTANCE, FEATURE_LAYER_MAPPER)) {
while(it.hasNext()) {
LayerContents lc = it.next();
featureLoader.accept(lc);
}
}
}
/**
* Some config directories in GeoServer are used to store workspace specific configurations,
* identify them so that we don't log complaints about their existence
*
* @param f
*
*/
private boolean isConfigDirectory(Resource dir) {
String name = dir.name();
boolean result = "styles".equals(name) || "layergroups".equals(name);
return result;
}
/**
* Reads the legacy (1.x) catalog from disk.
*/
Catalog readLegacyCatalog(Resource f, XStreamPersister xp) throws Exception {
Catalog catalog2 = new CatalogImpl();
catalog2.setResourceLoader(resourceLoader);
//add listener now as a converter which will convert from the old style
// data directory to the new
GeoServerPersister p = new GeoServerPersister( resourceLoader, xp );
if ( !legacy ) {
catalog2.addListener( p );
}
LegacyCatalogImporter importer = new LegacyCatalogImporter(catalog2);
importer.setResourceLoader(resourceLoader);
importer.imprt(resourceLoader.getBaseDirectory());
if ( !legacy ) {
catalog2.removeListener( p );
}
if ( !legacy ) {
//copy files from old feature type directories to new
Resource featureTypesDir = resourceLoader.get( "featureTypes" );
if ( featureTypesDir != null ) {
LegacyCatalogReader creader = new LegacyCatalogReader();
creader.read( f );
Map<String,Map<String,Object>> dataStores = creader.dataStores();
for ( Resource featureTypeDir : featureTypesDir.list() ) {
if ( featureTypeDir.getType() != Type.DIRECTORY ) {
continue;
}
Resource featureTypeInfo = featureTypeDir.get("info.xml" );
if ( !Resources.exists(featureTypeInfo) ) {
continue;
}
LegacyFeatureTypeInfoReader reader = new LegacyFeatureTypeInfoReader();
reader.read( featureTypeInfo );
Map<String,Object> dataStore = dataStores.get( reader.dataStore() );
if ( dataStore == null ) {
continue;
}
String namespace = (String) dataStore.get( "namespace" );
Resource destFeatureTypeDir =
resourceLoader.get( Paths.path("workspaces", namespace, reader.dataStore(), reader.name()) );
if ( destFeatureTypeDir != null ) {
//copy all the files over
for ( Resource file : featureTypeDir.list() ) {
if ( file.getType() == Type.RESOURCE && !featureTypeInfo.equals( file ) ) {
IOUtils.copy( file.in(), destFeatureTypeDir.get(file.name()).out() ) ;
}
}
}
}
}
//rename catalog.xml
f.renameTo( f.parent().get("catalog.xml.old" ) );
}
return catalog2;
}
protected void readConfiguration(GeoServer geoServer, XStreamPersister xp) throws Exception {
//look for services.xml, if it exists assume we are dealing with
// an old data directory
Resource f = resourceLoader.get( "services.xml" );
if (!Resources.exists(f)) {
//assume 2.x style
f = resourceLoader.get( "global.xml");
if ( Resources.exists(f) ) {
try {
GeoServerInfo global = depersist(xp, f, GeoServerInfo.class);
geoServer.setGlobal( global );
} catch (Exception e) {
LOGGER.log(Level.WARNING, "Failed to load global configuration file '" + f.name() + "'" , e );
}
}
//load logging
f = resourceLoader.get( "logging.xml" );
if ( Resources.exists(f) ) {
try {
LoggingInfo logging = depersist(xp, f, LoggingInfo.class );
geoServer.setLogging( logging );
} catch (Exception e) {
LOGGER.log(Level.WARNING, "Failed to load logging configuration file '" + f.name() + "'" , e );
}
}
// load workspace specific settings
Resource workspaces = resourceLoader.get("workspaces");
if (Resources.exists(workspaces)) {
for (Resource dir : workspaces.list()) {
if (dir.getType() != Type.DIRECTORY) continue;
f = dir.get("settings.xml");
if (Resources.exists(f)) {
try {
SettingsInfo settings = depersist(xp, f, SettingsInfo.class );
geoServer.add(settings);
} catch (Exception e) {
LOGGER.log(Level.WARNING, "Failed to load configuration file '" + f.name() + "' for workspace " + dir.name() , e );
}
}
}
}
//load services
final List<XStreamServiceLoader> loaders =
GeoServerExtensions.extensions( XStreamServiceLoader.class );
loadServices(resourceLoader.get(""), true, loaders, geoServer);
//load services specific to workspace
if (workspaces != null) {
for (Resource dir : workspaces.list()) {
if (dir.getType() != Type.DIRECTORY) continue;
loadServices(dir, false, loaders, geoServer);
}
}
} else {
//add listener now as a converter which will convert from the old style
// data directory to the new
GeoServerPersister p = new GeoServerPersister( resourceLoader, xp );
geoServer.addListener( p );
//import old style services.xml
new LegacyConfigurationImporter(geoServer).imprt(resourceLoader.getBaseDirectory());
geoServer.removeListener( p );
//rename the services.xml file
f.renameTo( f.parent().get("services.xml.old" ) );
}
}
void loadStyles(Resource styles, Catalog catalog, XStreamPersister xp) throws IOException {
Filter<Resource> styleFilter = r -> XML_FILTER.accept(r) && !Resources.exists(styles.get(r.name() + ".xml"));
try (AsynchResourceIterator<byte[]> it = new AsynchResourceIterator<>(styles, styleFilter, r -> r.getContents())) {
while (it.hasNext()) {
try {
StyleInfo s = depersist(xp, it.next(), StyleInfo.class);
catalog.add(s);
if(LOGGER.isLoggable(Level.INFO)) {
LOGGER.info("Loaded style '" + s.getName() + "'");
}
} catch (Exception e) {
LOGGER.log(Level.WARNING, "Failed to load style", e);
}
}
}
}
void loadLayerGroups(Resource layerGroups, Catalog catalog, XStreamPersister xp) {
try (AsynchResourceIterator<byte[]> it = new AsynchResourceIterator<>(layerGroups,
XML_FILTER, r -> r.getContents())) {
while (it.hasNext()) {
try {
LayerGroupInfo lg = depersist(xp, it.next(), LayerGroupInfo.class);
if (lg.getLayers() == null || lg.getLayers().size() == 0) {
LOGGER.warning(
"Skipping empty layer group '" + lg.getName() + "', it is invalid");
continue;
}
catalog.add(lg);
LOGGER.info("Loaded layer group '" + lg.getName() + "'");
} catch (Exception e) {
LOGGER.log(Level.WARNING, "Failed to load layer group", e);
}
}
}
}
void loadServices(Resource directory, boolean global, List<XStreamServiceLoader> loaders, GeoServer geoServer) {
for ( XStreamServiceLoader<ServiceInfo> l : loaders ) {
try {
ServiceInfo s = l.load( geoServer, directory);
if (!global && s.getWorkspace() == null) continue;
geoServer.add( s );
LOGGER.info( "Loaded service '" + s.getId() + "', " + (s.isEnabled()?"enabled":"disabled") );
}
catch( Throwable t ) {
if (Resources.exists(directory)) {
LOGGER.log(Level.SEVERE,
"Failed to load the service configuration in directory: " + directory
+ " with loader for " + l.getServiceClass(),
t);
} else {
LOGGER.log(
Level.SEVERE,
"Failed to load the root service configuration with loader for "
+ l.getServiceClass(), t);
}
}
}
}
/**
* Helper method which uses xstream to persist an object as xml on disk.
*/
void persist( XStreamPersister xp, Object obj, Resource f ) throws Exception {
BufferedOutputStream out = new BufferedOutputStream( f.out() );
xp.save( obj, out );
out.flush();
out.close();
}
/**
* Helper method which uses xstream to depersist an object as xml from disk.
*/
<T> T depersist( XStreamPersister xp, Resource f , Class<T> clazz ) throws IOException {
try(InputStream in = new ByteArrayInputStream(f.getContents())) {
return xp.load( in, clazz );
}
}
/**
* Helper method which uses xstream to depersist an object as xml from disk.
*/
static <T> T depersist( XStreamPersister xp, byte[] contents , Class<T> clazz ) throws IOException {
try(InputStream in = new ByteArrayInputStream(contents)) {
return xp.load( in, clazz );
}
}
public void destroy() throws Exception {
//dispose
geoserver.dispose();
}
}