/* (c) 2014 - 2016 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.catalog;
import static org.junit.Assert.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.List;
import org.geoserver.catalog.CascadeRemovalReporter.ModificationType;
import org.geoserver.catalog.event.CatalogListener;
import org.geoserver.catalog.impl.ModificationProxy;
import org.geoserver.config.GeoServerPersister;
import org.geoserver.data.test.MockData;
import org.geoserver.data.test.SystemTestData;
import org.geoserver.platform.GeoServerExtensions;
import org.geoserver.platform.GeoServerExtensionsHelper;
import org.geoserver.security.decorators.SecuredLayerGroupInfo;
import org.geoserver.test.GeoServerSystemTestSupport;
import org.geoserver.test.SystemTest;
import org.geoserver.test.TestSetup;
import org.geoserver.test.TestSetupFrequency;
import org.geotools.referencing.CRS;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.NoSuchAuthorityCodeException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
@Category(SystemTest.class)
@TestSetup(run=TestSetupFrequency.REPEAT)
public class CatalogIntegrationTest extends GeoServerSystemTestSupport {
@Override
protected void setUpTestData(SystemTestData testData) throws Exception {
super.setUpTestData(testData);
testData.setUpDefaultRasterLayers();
GeoServerExtensions extension = GeoServerExtensions.bean(GeoServerExtensions.class);
if( extension == null ){
GeoServerExtensionsHelper.init( this.applicationContext );
}
File root = testData.getDataDirectoryRoot();
File defaultWorkspace = new File(root, "workspaces/default.xml");
if(defaultWorkspace.exists()) {
defaultWorkspace.delete();
}
}
@Test
public void testWorkspaceRemoveAndReadd() {
// remove all workspaces
Catalog catalog = getCatalog();
NamespaceInfo defaultNamespace = catalog.getDefaultNamespace();
WorkspaceInfo defaultWs = catalog.getDefaultWorkspace();
List<WorkspaceInfo> workspaces = catalog.getWorkspaces();
CascadeDeleteVisitor visitor = new CascadeDeleteVisitor(catalog);
for (WorkspaceInfo ws : workspaces) {
visitor.visit(ws);
}
assertEquals(0, catalog.getWorkspaces().size());
assertEquals(0, catalog.getNamespaces().size());
// add back one (this would NPE)
catalog.add(defaultNamespace);
catalog.add(defaultWs);
assertEquals(1, catalog.getWorkspaces().size());
assertEquals(1, catalog.getNamespaces().size());
// get back by name (this would NPE too)
assertNotNull(catalog.getNamespaceByURI(defaultNamespace.getURI()));
}
/**
* Checks that the namespace/workspace listener keeps on working after
* a catalog reload
*/
@Test
public void testNamespaceWorkspaceListenerAttached() throws Exception {
Catalog catalog = getCatalog();
NamespaceInfo ns = catalog.getNamespaceByPrefix(MockData.CITE_PREFIX);
String newName = "XYWZ1234";
ns.setPrefix(newName);
catalog.save(ns);
assertNotNull(catalog.getWorkspaceByName(newName));
assertNotNull(catalog.getNamespaceByPrefix(newName));
// force a reload
int listenersBefore = catalog.getListeners().size();
getGeoServer().reload();
int listenersAfter = catalog.getListeners().size();
assertEquals(listenersBefore, listenersAfter);
// check the NamespaceWorkspaceListener is still attached and working
ns = catalog.getNamespaceByPrefix(newName);
ns.setPrefix(MockData.CITE_PREFIX);
catalog.save(ns);
assertNotNull(catalog.getWorkspaceByName(MockData.CITE_PREFIX));
// make sure we only have one resource pool listener and one catalog persister
int countCleaner = 0;
int countPersister = 0;
for (CatalogListener listener : catalog.getListeners()) {
if(listener instanceof ResourcePool.CacheClearingListener) {
countCleaner++;
} else if(listener instanceof GeoServerPersister) {
countPersister++;
}
}
assertEquals(1, countCleaner);
assertEquals(1, countPersister);
}
@Test
public void modificationProxySerializeTest() throws Exception {
Catalog catalog = getCatalog();
// workspace
WorkspaceInfo ws = catalog.getWorkspaceByName(MockData.CITE_PREFIX);
WorkspaceInfo ws2 = serialize(ws);
assertSame(ModificationProxy.unwrap(ws), ModificationProxy.unwrap(ws2));
// namespace
NamespaceInfo ns = catalog.getNamespaceByPrefix(MockData.CITE_PREFIX);
NamespaceInfo ns2 = serialize(ns);
assertSame(ModificationProxy.unwrap(ns), ModificationProxy.unwrap(ns2));
// data store and related objects
DataStoreInfo ds = catalog.getDataStoreByName(MockData.CITE_PREFIX);
DataStoreInfo ds2 = serialize(ds);
assertSame(ModificationProxy.unwrap(ds), ModificationProxy.unwrap(ds2));
assertSame(ModificationProxy.unwrap(ds.getWorkspace()), ModificationProxy.unwrap(ds2.getWorkspace()));
// coverage store and related objects
CoverageStoreInfo cs = catalog.getCoverageStoreByName(MockData.TASMANIA_DEM.getLocalPart());
CoverageStoreInfo cs2 = serialize(cs);
assertSame(ModificationProxy.unwrap(cs), ModificationProxy.unwrap(cs2));
assertSame(ModificationProxy.unwrap(cs.getWorkspace()), ModificationProxy.unwrap(cs2.getWorkspace()));
// feature type and related objects
FeatureTypeInfo ft = catalog.getFeatureTypeByName(getLayerId(MockData.BRIDGES));
FeatureTypeInfo ft2 = serialize(ft);
assertSame(ModificationProxy.unwrap(ft), ModificationProxy.unwrap(ft2));
assertSame(ModificationProxy.unwrap(ft.getStore()), ModificationProxy.unwrap(ft2.getStore()));
// coverage and related objects
CoverageInfo ci = catalog.getCoverageByName(getLayerId(MockData.TASMANIA_DEM));
CoverageInfo ci2 = serialize(ci);
assertSame(ModificationProxy.unwrap(ci), ModificationProxy.unwrap(ci2));
assertSame(ModificationProxy.unwrap(ci.getStore()), ModificationProxy.unwrap(ci.getStore()));
// style
StyleInfo streamsStyle = catalog.getStyleByName("Streams");
StyleInfo si2 = serialize(streamsStyle);
assertSame(ModificationProxy.unwrap(streamsStyle), ModificationProxy.unwrap(si2));
// layer and related objects
LayerInfo li = catalog.getLayerByName(getLayerId(MockData.BRIDGES));
// ... let's add an extra style
li.getStyles().add(streamsStyle);
catalog.save(li);
LayerInfo li2 = serialize(li);
assertSame(ModificationProxy.unwrap(li), ModificationProxy.unwrap(li2));
assertSame(ModificationProxy.unwrap(li.getResource()), ModificationProxy.unwrap(li2.getResource()));
assertSame(ModificationProxy.unwrap(li.getDefaultStyle()), ModificationProxy.unwrap(li2.getDefaultStyle()));
assertSame(ModificationProxy.unwrap(li.getStyles().iterator().next()), ModificationProxy.unwrap(li2.getStyles().iterator().next()));
// try a group layer
CatalogBuilder cb = new CatalogBuilder(catalog);
LayerGroupInfo lg = catalog.getFactory().createLayerGroup();
lg.getLayers().add(catalog.getLayerByName(getLayerId(MockData.ROAD_SEGMENTS)));
lg.getLayers().add(catalog.getLayerByName(getLayerId(MockData.PONDS)));
cb.calculateLayerGroupBounds(lg);
lg.setName("test-lg");
catalog.add(lg);
// ... make sure we get a proxy
lg = catalog.getLayerGroupByName("test-lg");
if (lg instanceof SecuredLayerGroupInfo) {
lg = ((SecuredLayerGroupInfo) lg).unwrap(LayerGroupInfo.class);
}
LayerGroupInfo lg2 = serialize(lg);
assertSame(ModificationProxy.unwrap(lg), ModificationProxy.unwrap(lg2));
assertSame(ModificationProxy.unwrap(lg.getLayers().get(0)), ModificationProxy.unwrap(lg2.getLayers().get(0)));
assertSame(ModificationProxy.unwrap(lg.getLayers().get(1)), ModificationProxy.unwrap(lg2.getLayers().get(1)));
// now check a half modified proxy
LayerInfo lim = catalog.getLayerByName(getLayerId(MockData.BRIDGES));
// ... let's add an extra style
lim.setDefaultStyle(streamsStyle);
lim.getStyles().add(streamsStyle);
// clone and check
LayerInfo lim2 = serialize(lim);
assertSame(ModificationProxy.unwrap(lim.getDefaultStyle()), ModificationProxy.unwrap(lim2.getDefaultStyle()));
assertSame(ModificationProxy.unwrap(lim.getStyles().iterator().next()), ModificationProxy.unwrap(lim2.getStyles().iterator().next()));
// mess a bit with the metadata map too
String key = "workspaceKey";
lim.getMetadata().put(key, ws);
LayerInfo lim3 = serialize(lim);
assertSame(ModificationProxy.unwrap(lim), ModificationProxy.unwrap(lim3));
assertSame(ModificationProxy.unwrap(lim.getMetadata().get(key)),
ModificationProxy.unwrap(lim3.getMetadata().get(key)));
}
/**
* Serializes and de-serializes the provided object
*
* @param object
*
* @throws IOException
* @throws ClassNotFoundException
*/
<T> T serialize(T object) throws IOException, ClassNotFoundException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(object);
oos.close();
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (T) ois.readObject();
}
@Test
public void testCascadeDeleteWorkspaceSpecific() throws Exception {
Catalog catalog = getCatalog();
WorkspaceInfo ws = catalog.getWorkspaceByName(MockData.ROAD_SEGMENTS.getPrefix());
// create a workspace specific group
CatalogBuilder cb = new CatalogBuilder(catalog);
LayerGroupInfo lg = catalog.getFactory().createLayerGroup();
lg.getLayers().add(catalog.getLayerByName(getLayerId(MockData.ROAD_SEGMENTS)));
lg.getLayers().add(catalog.getLayerByName(getLayerId(MockData.STREAMS)));
cb.calculateLayerGroupBounds(lg);
lg.setName("test-lg");
lg.setWorkspace(ws);
catalog.add(lg);
// make a style a workspace specific
StyleInfo style = catalog.getStyleByName(MockData.ROAD_SEGMENTS.getLocalPart());
style.setWorkspace(ws);
catalog.save(style);
// check we are getting the groups and styles reported properly
CascadeRemovalReporter reporter = new CascadeRemovalReporter(catalog);
ws.accept(reporter);
List<StyleInfo> styles = reporter.getObjects(StyleInfo.class, ModificationType.DELETE);
assertEquals(1, styles.size());
assertEquals(style, styles.get(0));
List<LayerGroupInfo> groups = reporter.getObjects(LayerGroupInfo.class,
ModificationType.DELETE);
assertEquals(1, groups.size());
assertEquals(lg, groups.get(0));
// now remove for real
CascadeDeleteVisitor remover = new CascadeDeleteVisitor(catalog);
ws.accept(remover);
assertNull(catalog.getWorkspaceByName(ws.getName()));
assertNull(catalog.getStyleByName(style.getName()));
assertNull(catalog.getLayerGroupByName(lg.getName()));
}
@Test
public void testReprojectLayerGroup()
throws NoSuchAuthorityCodeException, FactoryException, Exception {
Catalog catalog = getCatalog();
CatalogBuilder cb = new CatalogBuilder(catalog);
LayerGroupInfo lg = catalog.getFactory().createLayerGroup();
LayerInfo l = catalog.getLayerByName(getLayerId(MockData.ROAD_SEGMENTS));
lg.getLayers().add(l);
lg.setName("test-reproject");
// EPSG:4901 "equivalent" but different uom
String wkt = "GEOGCS[\"GCS_ATF_Paris\",DATUM[\"D_ATF\",SPHEROID[\"Plessis_1817\",6376523.0,308.64]],PRIMEM[\"Paris\",2.337229166666667],UNIT[\"Grad\",0.01570796326794897]]";
CoordinateReferenceSystem lCrs = CRS.parseWKT(wkt);
((FeatureTypeInfo)l.getResource()).setSRS(null);
((FeatureTypeInfo)l.getResource()).setNativeCRS(lCrs);
assertNull(CRS.lookupEpsgCode(lCrs, false));
// Use the real thing now
CoordinateReferenceSystem lgCrs = CRS.decode("EPSG:4901");
assertNotNull(CRS.lookupEpsgCode(lgCrs, false));
//Reproject our layer group to EPSG:4901. We expect it to have an EPSG code.
cb.calculateLayerGroupBounds(lg, lgCrs);
assertNotNull(CRS.lookupEpsgCode(lg.getBounds().getCoordinateReferenceSystem(), false));
}
}