Hi Jody,

I used the CollectionDataStore and redesigned it a bit. I append three classes 
(MemoryService, CollectionsFeatureStore and a event class) and I would like to 
get some feedback, whether it fits into the architecture of geotools.

Some use cases:
-       got some attribute filtered objects in client 
-       display them on map and interact with them to perform some spatial 
analysis
-       select some objects in a client table and select them in map to 
(FidFilter)
-       select some objects in map and get the selection in client table 
synchronized

Are there any limitations in geotools we didn’t reached yet if we would use the 
appended classes? Are ther other ways? Right now it’s not a requirement to get 
Features edited in map. The map should be a viewer for this kind of data. In 
addition the user should be able to edit other datasources in future (WFS-T or 
perhaps shapefiles).

Regards 
Frank
 
> > Hello,
> >
> > I?m currently using the MemoryFeatureCollection to show in memory features 
> > on map but I have some problems adding an empty layer to mapContext.
> Hi Frank; you are certaintly at the edge of what is expected of 
> MemoryFeatureCollection and MemoryDataStore (or the default feature 
> collection implementation). The implementation is not very smart; often 
> taking the first feature out of the collection and asking for its 
> FeatureType for example.
>
> What I would like to see is a series of memory feature collection 
> implementations that are targeted at different needs.

 
> >  I don't know whether it should be a feature or if it is a bug. I created a 
> > FeatureType and then a MemoryFeatureCollection for that. I?m using GeoTools 
> > version 2.5.2 and its swing components. After adding the layer to map I got 
> > exceptions:
> >
> > First (creating a MapLayer using the FeatureCollection):
> >
> > ...
> >
> > I guess the main problem is the DefaultFeatureType.EMPTY creation in 
> > CollectionDataStore.
> >
> > Second (creating a MapLayer using the DataStore):
> > I tried creating a MemoryDataStore with called the createSchema Method to 
> > get an empty layer to map. BUT if using the ?zoom to layer? method in layer 
> > entry in Table of Contents an other exception was thrown:
> >
> > I guess the MemoryDataStore getBounds(Query query) should have a behaviour 
> > like in CollectionDataStore getBoundsInternal :
> >
> >         ReferencedEnvelope envelope = new ReferencedEnvelope( 
> > featureType.getCoordinateReferenceSystem() );
> >
> > If the FeatureType is well defined it would work very well except creating 
> > a MapLayer like described above.
> >   
> It looks like some of the problems you are turning up have more to do 
> with testing a boundary condition (ie what to do when there are no 
> contents) then anything else.
> > Thank you  for any advice. Does anybody use the kind of Collections / 
> > DataStores ? Should a create a ticket in JIRA?
> >   
> If you would like to report these as bugs (and please check to see if 
> they are reported already) I would be happy to review any patches you 
> can provide. Things like your ReferencedEnvelope suggestion should be 
> easy to do; however we should check the API contract and see what is 
> expected of an empty collection; perhaps we have a chance to improve the 
> javadocs here.
> 
> Thanks for the report :-)
> Jody
> 
> 


__________________________________________________________________
Deutschlands größte Online-Videothek schenkt Ihnen 12.000 Videos!*
http://entertainment.web.de/de/entertainment/maxdome/index.html

import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.geotools.data.AbstractDataStore;
import org.geotools.data.FeatureReader;
import org.geotools.data.Transaction;
import org.geotools.data.collection.DelegateFeatureReader;
import org.geotools.feature.CollectionEvent;
import org.geotools.feature.CollectionListener;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureType;

import com.vividsolutions.jts.geom.Envelope;


public class CollectionsDataStore extends AbstractDataStore implements CollectionListener {
  
  private static final Logger LOG = Logger
      .getLogger(CollectionsDataStore.class);
  private Set<ServiceListener> serviceListeners = new HashSet<ServiceListener>();
  
  private final Map<FeatureType, FeatureCollection> collectionMap = new HashMap<FeatureType, FeatureCollection>();
  private final Map<String, FeatureType> typeMap = new HashMap<String, FeatureType>();
  
  public void addFeatureCollection(FeatureCollection featureCollection) throws IOException {
    FeatureType featureType = featureCollection.getFeatureType();
    
    createSchema(featureType);
    featureCollection.addListener(this);
    collectionMap.put(featureType, featureCollection);
  }
  
  @Override
  public void createSchema(FeatureType featureType) throws IOException {
    if (typeMap.containsKey(featureType.getTypeName())) {
      // force replace elements from older collection with the new one
      removeSchema(featureType);
//      throw new IOException("type already defined : " + featureType.getTypeName());
    }
    typeMap.put(featureType.getTypeName(), featureType);

    // fire schema changedEvent to get the MemoryService refreshed
    fireSchemaChanged(new SchemaChangedEvent(SchemaChangedEventType.CREATED, featureType));
  }
  
  public void removeSchema(FeatureType featureType) {
    if (typeMap.containsKey(featureType.getTypeName())) {
      typeMap.remove(featureType.getTypeName());
      FeatureCollection featureCollection = collectionMap.get(featureType);
      featureCollection.removeListener(this);
      collectionMap.remove(featureType);
      fireSchemaChanged(new SchemaChangedEvent(SchemaChangedEventType.DELETED, featureType));
    }
  }
  
  @Override
  protected FeatureReader getFeatureReader(String typeName) throws IOException {
    FeatureType featureType = typeMap.get(typeName);
    if (featureType == null) {
      throw new IOException("Type not defined " + typeName);
    }
    
    return new DelegateFeatureReader(featureType, collectionMap.get(featureType).features());
  }

  @Override
  public FeatureType getSchema(String typeName) throws IOException {
    return typeMap.get(typeName);
  }

  @Override
  public String[] getTypeNames() throws IOException {
    return typeMap.keySet().toArray(new String[0]);
  }
  
  @Override
  public void collectionChanged(CollectionEvent tce) {
    FeatureCollection featureCollection = tce.getCollection();
    FeatureType featureType = featureCollection.getFeatureType();
    String typeName = featureType.getTypeName();
    Envelope bounds = featureCollection.getBounds();
    
    switch (tce.getEventType()) {
    case CollectionEvent.FEATURES_ADDED:
      listenerManager.fireFeaturesAdded(typeName, Transaction.AUTO_COMMIT,
          bounds, false);

      break;

    case CollectionEvent.FEATURES_CHANGED:
      listenerManager.fireFeaturesChanged(typeName, Transaction.AUTO_COMMIT,
          bounds, false);

      break;

    case CollectionEvent.FEATURES_REMOVED:
      listenerManager.fireFeaturesRemoved(typeName, Transaction.AUTO_COMMIT,
          bounds, false);

      break;
    }
  }
  
  public void addServiceListener(ServiceListener listener) {
    serviceListeners.add(listener);
  }

  public void removeServiceListener(ServiceListener listener) {
    serviceListeners.remove(listener);
  }
  
  private void fireSchemaChanged(SchemaChangedEvent event) {
    for (Iterator<ServiceListener> iterator = serviceListeners.iterator(); iterator
        .hasNext();) {
      ServiceListener listener = iterator.next();
      try {
        listener.schemaChanged(event);
      } catch (Exception e) {
        LOG.error("Listener has thrown an error", e);
      }
    }
  }
}
import java.io.IOException;
import java.io.Serializable;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.geotools.catalog.AbstractService;
import org.geotools.catalog.GeoResource;
import org.geotools.catalog.ResolveChangeListener;
import org.geotools.catalog.ServiceInfo;
import org.geotools.catalog.defaults.DefaultServiceInfo;
import org.geotools.data.DataStore;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureType;
import org.geotools.util.NullProgressListener;
import org.geotools.util.ProgressListener;

public class MemoryService extends AbstractService {

  private static final Logger LOG = Logger.getLogger(MemoryService.class);
  
  public static final URI ID;

  static class ScratchServiceInfo extends DefaultServiceInfo {

    public ScratchServiceInfo() {
      super();
    }

    public String getTitle() {
      return "Scratch";
    }

    @Override
    public String getDescription() {
      return getTitle();
    }
  }
  
  static {
    try {
      ID = new URI("http://my-namespace.org";);
    } catch (URISyntaxException e) {
      throw new RuntimeException(e);
    }
  }
  /** info object * */
  private ScratchServiceInfo info;

  /** the data store * */
  private volatile CollectionsDataStore ds;

  private volatile List<MemoryGeoResource> memberList;

  private URI id;

  private final List<ResolveChangeListener> resolveListeners = new ArrayList<ResolveChangeListener>();

  private static MemoryService instance;
  
  public synchronized static MemoryService getInstance() {
    if (instance == null) {
      instance = new MemoryService(ID);
    }
    return instance;
  }
  
  /**
   * Creates a GeoResource within the MemoryService with the given FeatureCollection
   * @param featureCollection
   * @return
   */
  public static GeoResource createResource(FeatureCollection featureCollection) {
    ProgressListener monitor = new NullProgressListener();
    MemoryService service = MemoryService.getInstance();
    try {
      CollectionsDataStore ds = (CollectionsDataStore) service.resolve(DataStore.class, monitor);
      if (ds != null) {
        ds.addFeatureCollection(featureCollection);
      }
      List members = service.members(monitor);
      for (Iterator iterator = members.iterator(); iterator.hasNext();) {
        Object member = iterator.next();
        if (member instanceof MemoryGeoResource) {
          FeatureType ft = (FeatureType) ((MemoryGeoResource)member).resolve(FeatureType.class, monitor);
          if (ft != null && ft.equals(featureCollection.getFeatureType())) {
            return (GeoResource)member;
          }
        }
        
      }
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    return null;
  }
  private MemoryService(URI id) {
    super(null);
    this.id = id;
  }

  @Override
  public Map<String, Serializable> getConnectionParams() {
    // TODO
    return null;
  }

  public boolean canResolve(Class adaptee) {
    if (adaptee == null)
      return false;

    return (adaptee.isAssignableFrom(DataStore.class)
        || adaptee.isAssignableFrom(ServiceInfo.class) || adaptee
        .isAssignableFrom(List.class));

  }

  @Override
  public Object resolve(Class adaptee, ProgressListener listener)
      throws IOException {

    if (adaptee == null) {
      throw new NullPointerException("No adaptor specified"); //$NON-NLS-1$
    }

    if (adaptee.isAssignableFrom(DataStore.class))
      return adaptee.cast(getDS());
    if (adaptee.isAssignableFrom(ServiceInfo.class))
      return adaptee.cast(getInfo(listener));
    if (adaptee.isAssignableFrom(List.class))
      return adaptee.cast(members(listener));
    return null;
  }

  @Override
  public ServiceInfo getInfo(ProgressListener arg0) throws IOException {
    if (info == null) {
      info = new ScratchServiceInfo();
    }
    return info;
  }

  @Override
  public List members(ProgressListener arg0) throws IOException {
    DataStore ds = getDS();
    String[] types = ds.getTypeNames();
    if (memberList == null) {
      this.memberList = new ArrayList<MemoryGeoResource>();
      for (String type : types) {
        if (!found(type))
          this.memberList.add(new MemoryGeoResource(type, this));
      }
    }
    return this.memberList;
  }

  private boolean found(String type) {
    for (GeoResource resource : memberList) {
      if (type.equals(resource.getIdentifier().toString()))
        return true;
    }
    return false;
  }

  public Status getStatus() {
    return Status.CONNECTED;
  }

  public Throwable getMessage() {
    return null;
  }

  public URI getIdentifier() {
    return id;
  }

  protected synchronized DataStore getDS() {
    if (ds == null) {
      ds = new CollectionsDataStore();
      ds.addServiceListener(new ServiceListener() {

        @Override
        public void schemaChanged(final SchemaChangedEvent event) {
          memberList = null;
        }
      });
    }
    return ds;
  }
  
  public static URI getIdentifier(FeatureType featureType) throws URISyntaxException {
    URI namspace = featureType.getNamespace();
    return new URI(namspace.toString() + "#" + featureType.getTypeName());
  }
}
import org.geotools.feature.FeatureType;

public class SchemaChangedEvent {

  protected enum SchemaChangedEventType {
    DELETED,
    CREATED
  }

  private FeatureType featureType;
  private SchemaChangedEventType eventType;
  
  public FeatureType getFeatureType() {
    return featureType;
  }

  public SchemaChangedEventType getEventType() {
    return eventType;
  }

  public SchemaChangedEvent(SchemaChangedEventType eventType, FeatureType featureType) {
    this.eventType = eventType;
    this.featureType = featureType;
  }
}
------------------------------------------------------------------------------
This SF.net email is sponsored by:
SourcForge Community
SourceForge wants to tell your story.
http://p.sf.net/sfu/sf-spreadtheword
_______________________________________________
Geotools-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/geotools-devel

Reply via email to