/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2002-2011, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geoserver.data.geogit; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.logging.Logger; import org.geogit.api.MutableTree; import org.geogit.api.ObjectId; import org.geogit.api.Ref; import org.geogit.api.RevObject.TYPE; import org.geogit.api.RevTree; import org.geogit.repository.Repository; import org.geogit.storage.ObjectDatabase; import org.geogit.storage.ObjectReader; import org.geogit.storage.ObjectWriter; import org.geogit.storage.RefDatabase; import org.geogit.storage.WrappedSerialisingFactory; import org.geogit.storage.hessian.HessianSimpleFeatureTypeReader; import org.geogit.storage.hessian.HessianSimpleFeatureTypeWriter; import org.geoserver.data.versioning.VersioningDataStore; import org.geotools.data.DefaultServiceInfo; import org.geotools.data.FeatureReader; import org.geotools.data.FeatureWriter; import org.geotools.data.LockingManager; import org.geotools.data.Query; import org.geotools.data.SchemaNotFoundException; import org.geotools.data.ServiceInfo; import org.geotools.data.Transaction; import org.geotools.feature.NameImpl; import org.geotools.feature.simple.SimpleFeatureTypeBuilder; import org.geotools.util.logging.Logging; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.feature.type.Name; import org.opengis.filter.Filter; import com.google.common.base.Preconditions; import com.google.common.base.Throwables; public class GeoGitDataStore implements VersioningDataStore { private static final Logger LOGGER = Logging .getLogger(GeoGitDataStore.class); public static final String TYPE_NAMES_REF_TREE = "typeNames"; private static final String NULL_NAMESPACE = ""; private Repository repo; private final String defaultNamespace; public GeoGitDataStore(final Repository repo) throws IOException { this(repo, null); } public GeoGitDataStore(final Repository repo, final String defaultNamespace) throws IOException { Preconditions.checkNotNull(repo, "repository"); this.repo = repo; this.defaultNamespace = defaultNamespace; init(); } private void init() throws IOException { final RefDatabase refDatabase = repo.getRefDatabase(); final ObjectDatabase objectDatabase = repo.getObjectDatabase(); Ref typesTreeRef = refDatabase.getRef(TYPE_NAMES_REF_TREE); if (null == typesTreeRef) { LOGGER.info("Initializing type name references. Types tree does not exist"); final RevTree typesTree = objectDatabase.newTree(); ObjectId typesTreeId; try { WrappedSerialisingFactory serialisingFactory; serialisingFactory = WrappedSerialisingFactory.getInstance(); ObjectWriter<RevTree> treeWriter = serialisingFactory .createRevTreeWriter(typesTree); typesTreeId = objectDatabase.put(treeWriter); } catch (Exception e) { throw new IOException(e); } typesTreeRef = new Ref(TYPE_NAMES_REF_TREE, typesTreeId, TYPE.TREE); refDatabase.put(typesTreeRef); LOGGER.info("Type names tree reference initialized"); } else { LOGGER.info("Loading type name references"); List<Name> names = getNamesInternal(); LOGGER.fine("Managed types: " + names); } } public Repository getRepository() { return repo; } /** * @see org.geotools.data.DataAccess#getInfo() */ @Override public ServiceInfo getInfo() { DefaultServiceInfo si = new DefaultServiceInfo(); si.setDescription("GeoGIT DataStore"); si.setTitle("GeoGIT"); return si; } /** * @see org.geotools.data.DataAccess#dispose() */ @Override public void dispose() { // TODO Auto-generated method stub } private List<Name> getNamesInternal() throws IOException { final RefDatabase refDatabase = repo.getRefDatabase(); final ObjectDatabase objectDatabase = repo.getObjectDatabase(); final Ref typesTreeRef = refDatabase.getRef(TYPE_NAMES_REF_TREE); Preconditions.checkState(typesTreeRef != null); RevTree namespacesTree = objectDatabase.getTree(typesTreeRef .getObjectId()); Preconditions.checkState(null != namespacesTree, "Referenced types tree does not exist: " + typesTreeRef); List<Name> names = new ArrayList<Name>(); for (Iterator<Ref> namespaces = namespacesTree.iterator(null); namespaces .hasNext();) { final Ref namespaceRef = namespaces.next(); Preconditions.checkState(TYPE.TREE.equals(namespaceRef.getType())); final String nsUri = namespaceRef.getName(); final RevTree typesTree = objectDatabase.getTree(namespaceRef .getObjectId()); for (Iterator<Ref> simpleNames = typesTree.iterator(null); simpleNames .hasNext();) { final Ref typeNameRef = simpleNames.next(); final String simpleTypeName = typeNameRef.getName(); names.add(new NameImpl(nsUri, simpleTypeName)); } } return names; } /** * @see org.geotools.data.DataAccess#getNames() */ @Override public List<Name> getNames() throws IOException { return getNamesInternal(); } /** * @see org.geotools.data.DataStore#getTypeNames() * @see #getNames() */ @Override public String[] getTypeNames() throws IOException { final List<Name> names = getNames(); String[] simpleNames = new String[names.size()]; for (int i = 0; i < names.size(); i++) { simpleNames[i] = names.get(i).getLocalPart(); } return simpleNames; } /** * @see org.geotools.data.DataAccess#createSchema(org.opengis.feature.type.FeatureType) */ @Override public void createSchema(final SimpleFeatureType featureType) throws IOException { Preconditions.checkNotNull(featureType); SimpleFeatureType createType = featureType; LOGGER.info("Creating FeatureType " + createType.getName()); if (getNames().contains(createType.getName())) { throw new IOException(createType.getName() + " already exists"); } { // GeoServer calls createSchema with this namespace but then asks // for the one passed in // as the DataStore's namespace parameter final String ignoreNamespace = "http://www.opengis.net/gml"; Name name = createType.getName(); if ((ignoreNamespace.equals(name.getNamespaceURI()) || null == name .getNamespaceURI()) && null != defaultNamespace) { LOGGER.info("FeatureType to be created has no namespace, assigning DataStore's default: '" + defaultNamespace + "'"); SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder(); builder.setName(createType.getName().getLocalPart()); builder.setNamespaceURI(defaultNamespace); builder.addAll(createType.getAttributeDescriptors()); createType = builder.buildFeatureType(); } } final Name typeName = createType.getName(); final RefDatabase refDatabase = repo.getRefDatabase(); final ObjectDatabase objectDatabase = repo.getObjectDatabase(); final Ref typesTreeRef = refDatabase.getRef(TYPE_NAMES_REF_TREE); Preconditions.checkState(typesTreeRef != null); final RevTree namespacesRootTree = objectDatabase.getTree(typesTreeRef .getObjectId()); Preconditions.checkState(namespacesRootTree != null); final String namespace = null == typeName.getNamespaceURI() ? NULL_NAMESPACE : typeName.getNamespaceURI(); final String localName = typeName.getLocalPart(); try { final ObjectId featureTypeBlobId; // WrappedSerialisingFactory serialisingFactory; // serialisingFactory = WrappedSerialisingFactory.getInstance(); // featureTypeBlobId = objectDatabase.put(serialisingFactory // .createSimpleFeatureTypeWriter(createType)); featureTypeBlobId = objectDatabase.put(new HessianSimpleFeatureTypeWriter(createType)); final List<String> namespaceTreePath = Collections .singletonList(namespace); MutableTree namespaceTree = objectDatabase.getOrCreateSubTree( namespacesRootTree, namespaceTreePath); namespaceTree.put(new Ref(localName, featureTypeBlobId, TYPE.BLOB)); final MutableTree root = namespacesRootTree.mutable(); final ObjectId newTypeRefsTreeId; newTypeRefsTreeId = objectDatabase.writeBack(root, namespaceTree, namespaceTreePath); final Ref newTypesTreeRef = new Ref(TYPE_NAMES_REF_TREE, newTypeRefsTreeId, TYPE.TREE); refDatabase.put(newTypesTreeRef); } catch (IOException e) { throw e; } catch (Exception e) { Throwables.propagate(e); } } /** * @see org.geotools.data.DataAccess#getSchema(org.opengis.feature.type.Name) */ @Override public SimpleFeatureType getSchema(final Name name) throws IOException { Preconditions.checkNotNull(name); final RefDatabase refDatabase = repo.getRefDatabase(); final ObjectDatabase objectDatabase = repo.getObjectDatabase(); final Ref typesTreeRef = refDatabase.getRef(TYPE_NAMES_REF_TREE); Preconditions.checkState(typesTreeRef != null); final RevTree namespacesRootTree = objectDatabase.getTree(typesTreeRef .getObjectId()); Preconditions.checkState(namespacesRootTree != null); final String[] path = { name.getNamespaceURI() == null ? NULL_NAMESPACE : name .getNamespaceURI(), name.getLocalPart() }; final Ref typeRef = objectDatabase.getTreeChild(namespacesRootTree, path); if (typeRef == null) { throw new SchemaNotFoundException(name.toString()); } Preconditions.checkState(TYPE.BLOB.equals(typeRef.getType())); final ObjectId objectId = typeRef.getObjectId(); WrappedSerialisingFactory serialisingFactory; serialisingFactory = WrappedSerialisingFactory.getInstance(); // final ObjectReader<SimpleFeatureType> reader = serialisingFactory // .createSimpleFeatureTypeReader(name); final ObjectReader<SimpleFeatureType> reader = new HessianSimpleFeatureTypeReader(name); final SimpleFeatureType featureType = objectDatabase.get(objectId, reader); return featureType; } /** * @see org.geotools.data.DataStore#getSchema(java.lang.String) * @see #getSchema(Name) */ @Override public SimpleFeatureType getSchema(final String typeName) throws IOException { final List<Name> names = getNames(); for (Name name : names) { if (name.getLocalPart().equals(typeName)) { return getSchema(name); } } throw new SchemaNotFoundException(typeName); } /** * @see org.geotools.data.DataStore#getFeatureSource(java.lang.String) * @see #getFeatureSource(Name) */ @Override public GeoGitFeatureSource getFeatureSource(final String typeName) throws IOException { final List<Name> names = getNames(); for (Name name : names) { if (name.getLocalPart().equals(typeName)) { return getFeatureSource(name); } } throw new SchemaNotFoundException(typeName); } /** * @see org.geotools.data.DataStore#getFeatureSource(org.opengis.feature.type.Name) */ @Override public GeoGitFeatureSource getFeatureSource(final Name typeName) throws IOException { final SimpleFeatureType featureType = getSchema(typeName); return new GeoGitFeatureStore(featureType, this); } @Override public FeatureReader<SimpleFeatureType, SimpleFeature> getFeatureReader( Query query, Transaction transaction) throws IOException { throw new UnsupportedOperationException("not yet implemented"); } @Override public FeatureWriter<SimpleFeatureType, SimpleFeature> getFeatureWriter( String typeName, Filter filter, Transaction transaction) throws IOException { throw new UnsupportedOperationException("not yet implemented"); } @Override public FeatureWriter<SimpleFeatureType, SimpleFeature> getFeatureWriter( String typeName, Transaction transaction) throws IOException { throw new UnsupportedOperationException("not yet implemented"); } @Override public FeatureWriter<SimpleFeatureType, SimpleFeature> getFeatureWriterAppend( String typeName, Transaction transaction) throws IOException { throw new UnsupportedOperationException("not yet implemented"); } @Override public LockingManager getLockingManager() { return null; } /** * @see org.geotools.data.DataAccess#updateSchema(org.opengis.feature.type.Name, * org.opengis.feature.type.FeatureType) */ @Override public void updateSchema(Name typeName, SimpleFeatureType featureType) throws IOException { throw new UnsupportedOperationException("Not yet implemented"); } /** * @see org.geotools.data.DataStore#updateSchema(java.lang.String, * org.opengis.feature.simple.SimpleFeatureType) */ @Override public void updateSchema(String typeName, SimpleFeatureType featureType) throws IOException { throw new UnsupportedOperationException("Not yet implemented"); } }