/* (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.web.data.store; import static org.geoserver.catalog.Predicates.sortBy; import java.io.Serializable; import java.util.Arrays; import java.util.Comparator; import java.util.Iterator; import java.util.List; import org.apache.wicket.extensions.markup.html.repeater.util.SortParam; import org.apache.wicket.model.IModel; import org.apache.wicket.model.LoadableDetachableModel; import org.apache.wicket.model.Model; import org.geoserver.catalog.Catalog; import org.geoserver.catalog.CoverageStoreInfo; import org.geoserver.catalog.DataStoreInfo; import org.geoserver.catalog.Predicates; import org.geoserver.catalog.ResourcePool; import org.geoserver.catalog.StoreInfo; import org.geoserver.catalog.WorkspaceInfo; import org.geoserver.catalog.util.CloseableIterator; import org.geoserver.catalog.util.CloseableIteratorAdapter; import org.geoserver.web.GeoServerApplication; import org.geoserver.web.wicket.GeoServerDataProvider; import org.geotools.data.DataAccessFactory; import org.geotools.factory.CommonFactoryFinder; import org.opengis.coverage.grid.Format; import org.opengis.filter.Filter; import org.opengis.filter.FilterFactory2; import org.opengis.filter.sort.SortBy; import com.google.common.collect.Lists; /** * Data providers for the {@link StorePanel} */ @SuppressWarnings("serial") public class StoreProvider extends GeoServerDataProvider<StoreInfo> { static final Property<StoreInfo> DATA_TYPE = new AbstractProperty<StoreInfo>("datatype") { public IModel getModel(final IModel itemModel) { return new Model(itemModel) { @Override public Serializable getObject() { StoreInfo si = (StoreInfo) itemModel.getObject(); return (String) getPropertyValue(si); } }; } public Object getPropertyValue(StoreInfo item) { if (item instanceof DataStoreInfo) return "vector"; else return "raster"; } }; static final Property<StoreInfo> WORKSPACE = new BeanProperty<StoreInfo>( "workspace", "workspace.name"); static final Property<StoreInfo> NAME = new BeanProperty<StoreInfo>("name", "name"); final Property<StoreInfo> TYPE = new AbstractProperty<StoreInfo>("type") { public Object getPropertyValue(StoreInfo item) { String type = item.getType(); if(type != null) { return type; } try { ResourcePool resourcePool = getCatalog().getResourcePool(); if(item instanceof DataStoreInfo) { DataStoreInfo dsInfo = (DataStoreInfo) item; DataAccessFactory factory = resourcePool.getDataStoreFactory(dsInfo); if(factory != null) { return factory.getDisplayName(); } } else if(item instanceof CoverageStoreInfo) { Format format = resourcePool.getGridCoverageFormat((CoverageStoreInfo) item); if(format != null) { return format.getName(); } } } catch(Exception e) { // fine, we tried } return "?"; } }; static final Property<StoreInfo> ENABLED = new BeanProperty<StoreInfo>( "enabled", "enabled"); final List<Property<StoreInfo>> PROPERTIES = Arrays.asList(DATA_TYPE, WORKSPACE, NAME, TYPE, ENABLED); WorkspaceInfo workspace; public StoreProvider() { this(null); } public StoreProvider(WorkspaceInfo workspace) { this.workspace = workspace; } @Override protected List<StoreInfo> getItems() { throw new UnsupportedOperationException( "This method should not be being called! " + "We use the catalog streaming API"); } @Override protected List<Property<StoreInfo>> getProperties() { return PROPERTIES; } @Override protected Comparator<StoreInfo> getComparator(SortParam sort) { return super.getComparator(sort); } public IModel newModel(StoreInfo object) { return new StoreInfoDetachableModel((StoreInfo) object); } /** * A StoreInfo detachable model that holds the store id to retrieve it on demand from the * catalog */ static class StoreInfoDetachableModel extends LoadableDetachableModel { private static final long serialVersionUID = -6829878983583733186L; String id; public StoreInfoDetachableModel(StoreInfo store) { super(store); this.id = store.getId(); } @Override protected Object load() { Catalog catalog = GeoServerApplication.get().getCatalog(); StoreInfo storeInfo = catalog.getStore(id, StoreInfo.class); return storeInfo; } } @Override public long size() { Filter filter = getFilter(); filter = getWorkspaceFilter(filter); int count = getCatalog().count(StoreInfo.class, filter); return count; } @Override public int fullSize() { Filter filter = Predicates.acceptAll(); filter = getWorkspaceFilter(filter); int count = getCatalog().count(StoreInfo.class, filter); return count; } @Override public Iterator<StoreInfo> iterator(final long first, final long count) { Iterator<StoreInfo> iterator = filteredItems(first, count); if (iterator instanceof CloseableIterator) { // don't know how to force wicket to close the iterator, lets return // a copy. Shouldn't be much overhead as we're paging try { return Lists.newArrayList(iterator).iterator(); } finally { CloseableIteratorAdapter.close(iterator); } } else { return iterator; } } /** * Returns the requested page of layer objects after applying any keyword * filtering set on the page */ private Iterator<StoreInfo> filteredItems(long first, long count) { final Catalog catalog = getCatalog(); // global sorting final SortParam sort = getSort(); final Property<StoreInfo> property = getProperty(sort); SortBy sortOrder = null; if (sort != null) { if (property instanceof BeanProperty) { final String sortProperty = ((BeanProperty<StoreInfo>) property).getPropertyPath(); sortOrder = sortBy(sortProperty, sort.isAscending()); } else if (property == ENABLED) { sortOrder = sortBy("enabled", sort.isAscending()); } else if (property == TYPE) { sortOrder = sortBy("type", sort.isAscending()); } } else { sortOrder = sortBy("name", true); } final Filter filter = getWorkspaceFilter(getFilter()); //our already filtered and closeable iterator Iterator<StoreInfo> items = catalog.list(StoreInfo.class, filter, (int)first, (int)count, sortOrder); return items; } private Filter getWorkspaceFilter(Filter filter){ // Filter by workspace if present if(workspace != null){ FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(); Filter workspaceFilter = ff.equal(ff.property("workspace.id"), ff.literal(workspace.getId())); filter = ff.and(filter, workspaceFilter); } return filter; } }