net.refractions.udig.catalog.internal.shp.ShpServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for net.refractions.udig.catalog.internal.shp.ShpServiceImpl.java

Source

/*
 *    uDig - User Friendly Desktop Internet GIS client
 *    http://udig.refractions.net
 *    (C) 2004, Refractions Research Inc.
 *
 *    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 net.refractions.udig.catalog.internal.shp;

import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.Lock;

import net.refractions.udig.catalog.CatalogPlugin;
import net.refractions.udig.catalog.IDeletingSchemaService;
import net.refractions.udig.catalog.ICatalog;
import net.refractions.udig.catalog.ID;
import net.refractions.udig.catalog.IGeoResource;
import net.refractions.udig.catalog.IResolve;
import net.refractions.udig.catalog.IResolveChangeEvent;
import net.refractions.udig.catalog.IResolveDelta;
import net.refractions.udig.catalog.IService;
import net.refractions.udig.catalog.IServiceInfo;
import net.refractions.udig.catalog.URLUtils;
import net.refractions.udig.catalog.internal.CatalogImpl;
import net.refractions.udig.catalog.internal.ResolveChangeEvent;
import net.refractions.udig.catalog.internal.ResolveDelta;
import net.refractions.udig.catalog.shp.internal.Messages;
import net.refractions.udig.ui.ErrorManager;
import net.refractions.udig.ui.PlatformGIS;
import net.refractions.udig.ui.UDIGDisplaySafeLock;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.ui.PlatformUI;
import org.geotools.data.DefaultQuery;
import org.geotools.data.FeatureReader;
import org.geotools.data.Transaction;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.shapefile.ShapefileDataStoreFactory;
import org.geotools.data.shapefile.indexed.IndexedShapefileDataStore;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.filter.Filter;

import org.apache.commons.io.FilenameUtils;

/**
 * Connect to a shapefile
 * 
 * @author David Zwiers, Refractions Research
 * @since 0.6
 */
public class ShpServiceImpl extends IService implements IDeletingSchemaService {

    private URL url;
    private ID id;
    private Map<String, Serializable> params = null;

    /**
     * Construct <code>ShpServiceImpl</code>.
     * 
     * @param arg1
     * @param arg2
     */
    public ShpServiceImpl(URL url, Map<String, Serializable> params) {
        this.url = url;
        try {
            id = new ID(url);
        } catch (Throwable t) {
            t.printStackTrace();
        }
        this.params = params;
        Serializable memorymapped = params.get("memory mapped buffer"); //$NON-NLS-1$
        if (memorymapped == null) {
            memorymapped = false;
            try {
                File file = URLUtils.urlToFile(url);
                final int maxsize = 1024 * 2048;
                if (file.length() > maxsize) {
                    memorymapped = false;
                }
            } catch (Exception e) {
                memorymapped = false;
            }
        }
        if (!params.containsKey(ShapefileDataStoreFactory.CREATE_SPATIAL_INDEX.key)) {
            params.put(ShapefileDataStoreFactory.CREATE_SPATIAL_INDEX.key,
                    ShpPlugin.getDefault().isUseSpatialIndex());
        }
        if (!params.containsKey(ShapefileDataStoreFactory.DBFCHARSET.key)) {
            params.put(ShapefileDataStoreFactory.DBFCHARSET.key, "ISO-8859-1");
            // _p3: we rely on fix ISO setting, since the preference setting is not yet available in p3
            //ShpPlugin.getDefault().defaultCharset());
        }
    }

    /*
     * Required adaptions: <ul> <li>IServiceInfo.class <li>List.class
     * <IGeoResource> </ul>
     * 
     * @see net.refractions.udig.catalog.IService#resolve(java.lang.Class,
     *      org.eclipse.core.runtime.IProgressMonitor)
     */
    public <T> T resolve(Class<T> adaptee, IProgressMonitor monitor) throws IOException {

        if (monitor == null)
            monitor = new NullProgressMonitor();

        if (adaptee == null) {
            throw new NullPointerException("No adaptor specified"); //$NON-NLS-1$
        }
        if (adaptee.isAssignableFrom(ShapefileDataStore.class))
            return adaptee.cast(getDS(monitor));
        if (adaptee.isAssignableFrom(File.class))
            return adaptee.cast(toFile());
        return super.resolve(adaptee, monitor);
    }

    /*
     * @see net.refractions.udig.catalog.IResolve#canResolve(java.lang.Class)
     */
    public <T> boolean canResolve(Class<T> adaptee) {
        if (adaptee == null)
            return false;
        return adaptee.isAssignableFrom(ShapefileDataStore.class) || adaptee.isAssignableFrom(File.class)
                || super.canResolve(adaptee);
    }

    public void dispose(IProgressMonitor monitor) {
        if (members == null)
            return;

        int steps = (int) ((double) 99 / (double) members.size());
        for (IResolve resolve : members) {
            try {
                SubProgressMonitor subProgressMonitor = new SubProgressMonitor(monitor, steps);
                resolve.dispose(subProgressMonitor);
                subProgressMonitor.done();
            } catch (Throwable e) {
                ErrorManager.get().displayException(e, "Error disposing members of service: " + getIdentifier(), //$NON-NLS-1$
                        CatalogPlugin.ID);
            }
        }
    }

    /*
     * @see net.refractions.udig.catalog.IResolve#members(org.eclipse.core.runtime.IProgressMonitor)
     */
    public List<ShpGeoResourceImpl> resources(IProgressMonitor monitor) throws IOException {

        if (members == null) {
            getDS(monitor); // slap it to load datastore
            rLock.lock();
            try {
                if (members == null) {
                    members = new LinkedList<ShpGeoResourceImpl>();
                    String[] typenames = ds.getTypeNames();
                    if (typenames != null)
                        for (int i = 0; i < typenames.length; i++) {
                            members.add(new ShpGeoResourceImpl(this, typenames[i]));
                        }
                }
            } finally {
                rLock.unlock();
            }
        }
        return members;
    }

    private volatile List<ShpGeoResourceImpl> members = null;

    /*
     * @see net.refractions.udig.catalog.IService#getInfo(org.eclipse.core.runtime.IProgressMonitor)
     */
    protected IServiceInfo createInfo(IProgressMonitor monitor) throws IOException {
        getDS(monitor); // load ds
        if (info == null && ds != null) {
            rLock.lock();
            try {
                if (info == null) {
                    info = new ShpServiceInfo(this);
                }
            } finally {
                rLock.unlock();
            }
        }
        return info;
    }

    /*
     * @see net.refractions.udig.catalog.IService#getConnectionParams()
     */
    public Map<String, Serializable> getConnectionParams() {
        return params;
    }

    private Throwable msg = null;

    /**
     * Volatile cache of dataStore if created.
     */
    volatile ShapefileDataStore ds = null;

    protected final Lock rLock = new UDIGDisplaySafeLock();

    private final static Lock dsInstantiationLock = new UDIGDisplaySafeLock();

    ShapefileDataStore getDS(IProgressMonitor monitor) throws IOException {
        if (ds == null) {
            dsInstantiationLock.lock();
            try {
                if (ds == null) {
                    ShapefileDataStoreFactory dsf = new ShapefileDataStoreFactory();
                    if (dsf.canProcess(params)) {

                        try {
                            ds = dsf.createDataStore(params);
                            openIndexGenerationDialog(ds);
                            // hit it lightly to make sure it exists.
                            ds.getFeatureSource();

                        } catch (IOException e) {
                            msg = e;
                            try {
                                params.remove(ShapefileDataStoreFactory.CREATE_SPATIAL_INDEX.key);
                                ds = dsf.createDataStore(params);
                                // hit it lightly to make sure it exists.
                                ds.getFeatureSource();

                            } catch (Exception e2) {
                                msg = e2;
                                throw (IOException) new IOException().initCause(e2);
                            }
                        }
                    }
                }
            } finally {
                dsInstantiationLock.unlock();
            }
            IResolveDelta delta = new ResolveDelta(this, IResolveDelta.Kind.CHANGED);
            ResolveChangeEvent event = new ResolveChangeEvent(this, IResolveChangeEvent.Type.POST_CHANGE, delta);
            fire(event);
        }
        return ds;
    }

    private void fire(ResolveChangeEvent event) {
        ICatalog catalog = parent(new NullProgressMonitor());
        if (catalog instanceof CatalogImpl) {
            ((CatalogImpl) catalog).fire(event);
        }
    }

    private void openIndexGenerationDialog(final ShapefileDataStore ds) {
        rLock.lock();
        try {
            if (ds instanceof IndexedShapefileDataStore) {
                IndexedShapefileDataStore ids = (IndexedShapefileDataStore) ds;
                if (ids.isIndexed())
                    return;
                String name = getIdentifier().getFile();
                int lastIndexOf = name.lastIndexOf(File.separator);
                if (lastIndexOf > 0)
                    name = name.substring(lastIndexOf + 1);
                final String finalName = name;
                IRunnableWithProgress runnable = new IRunnableWithProgress() {

                    public void run(IProgressMonitor monitor)
                            throws InvocationTargetException, InterruptedException {
                        monitor.beginTask(Messages.ShpPreferencePage_createindex + " " + finalName, //$NON-NLS-1$
                                IProgressMonitor.UNKNOWN);
                        index(ds, ds.getTypeNames()[0]);
                        monitor.done();
                    }

                };
                if (PlatformUI.getWorkbench().isClosing() && false) {
                    try {
                        runnable.run(new NullProgressMonitor());
                    } catch (InvocationTargetException e) {
                        ShpPlugin.log("", e); //$NON-NLS-1$
                    } catch (InterruptedException e) {
                        ShpPlugin.log("", e); //$NON-NLS-1$
                    }
                } else {
                    PlatformGIS.runInProgressDialog(Messages.ShpServiceImpl_indexing + " " + finalName, true, //$NON-NLS-1$
                            runnable, false);
                }
            }
        } finally {
            rLock.unlock();
        }

    }

    private void index(final ShapefileDataStore ds, final String typename) {
        FeatureReader<SimpleFeatureType, SimpleFeature> reader = null;
        try {
            // smack Datastore to generate indices
            reader = ds.getFeatureReader(new DefaultQuery(typename, Filter.INCLUDE, new String[0]),
                    Transaction.AUTO_COMMIT);
        } catch (Exception e) {
            ShpPlugin.log("", e); //$NON-NLS-1$
        } finally {
            if (reader != null)
                try {
                    reader.close();
                } catch (IOException e) {
                    ShpPlugin.log("", e); //$NON-NLS-1$
                }
        }
    }

    /*
     * @see net.refractions.udig.catalog.IResolve#getStatus()
     */
    public Status getStatus() {
        return msg != null ? Status.BROKEN : ds == null ? Status.NOTCONNECTED : Status.CONNECTED;
    }

    /*
     * @see net.refractions.udig.catalog.IResolve#getMessage()
     */
    public Throwable getMessage() {
        return msg;
    }

    /*
     * @see net.refractions.udig.catalog.IResolve#getIdentifier()
     */
    public URL getIdentifier() {
        return url;
    }

    @Override
    public ID getID() {
        return id;
    }

    /**
     * The File as indicated in the connection parameters, may be null if we are representing a web resource.
     * @return file as indicated in the connection parameters, may be null if we are reprsenting a web resource
     */
    public File toFile() {
        Map<String, Serializable> parametersMap = getConnectionParams();
        URL url = (URL) parametersMap.get(ShapefileDataStoreFactory.URLP.key);
        return URLUtils.urlToFile(url);
    }

    public void deleteSchema(IGeoResource geores, IProgressMonitor monitor) throws IOException {
        File file = resolve(File.class, monitor);
        String baseName = FilenameUtils.getBaseName(file.getName());
        for (File f : file.getParentFile().listFiles()) {
            if (FilenameUtils.getBaseName(f.getName()).equals(baseName)) {
                System.out.println("deleting: " + f.getAbsolutePath());
                if (!f.delete()) {
                    throw new IOException("Unable to delete file: " + f.getAbsolutePath());
                }
            }
        }
    }

    /**
     * Allows to reset data source after *.prj file was written.
     */
    public void resetDataSource() {
        ds = null;
    }

}