/* Copyright (c) 2001 - 2009 TOPP - www.openplans.org. All rights reserved.
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.web.data.store;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.util.List;
import org.apache.wicket.markup.html.form.Form;
import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.CoverageStoreInfo;
import org.geoserver.catalog.DataStoreInfo;
import org.geoserver.catalog.ResourcePool;
import org.geoserver.catalog.StoreInfo;
import org.geoserver.web.CatalogIconFactory;
import org.geoserver.web.GeoServerApplication;
import org.geoserver.web.data.resource.DataStorePanelInfo;
import org.geotools.coverage.grid.io.AbstractGridFormat;
import org.geotools.data.DataAccessFactory;
/**
* Entry point to look up for StoreInfo related extension points
* <p>
* At least two {@link DataStorePanelInfo} should be provided by the application context in order to
* be used as the default ones when no specific panel info is contributed for a given store type,
* and they shall have the id property set to {@code "defaultVector"} and {@code "defaultRaster"}
* for {@link DataStoreInfo} and {@link CoverageStoreInfo} defaults respectively.
* </p>
*
* TODO: port the lookup of {@link DataStorePanelInfo} present in {@link CatalogIconFactory} here.
*
* @author Gabriel Roldan
*
*/
public class StoreExtensionPoints {
private StoreExtensionPoints() {
// do nothing
}
/**
* Finds out the {@link StoreEditPanel} that provides the edit form components for the given
* store.
*
* @param componentId
* the id for the returned panel
* @param editForm
* the form that's going to contain the components in the returned panel
* @param storeInfo
* the store being edited
* @param app
* the {@link GeoServerApplication} where to look for registered
* {@link DataStorePanelInfo}s
* @return a custom {@link StoreEditPanel} if there's one declared for the given store type, or
* a default one otherwise
*/
public static StoreEditPanel getStoreEditPanel(final String componentId, final Form editForm,
final StoreInfo storeInfo, final GeoServerApplication app) {
if (storeInfo == null) {
throw new NullPointerException("storeInfo param");
}
if (app == null) {
throw new NullPointerException("GeoServerApplication param");
}
DataStorePanelInfo panelInfo = findPanelInfo(storeInfo, app);
if (panelInfo == null || panelInfo.getComponentClass() == null) {
// there's either no panel info specific for this kind of store, or it provides no
// component class
panelInfo = getDefaultPanelInfo(storeInfo, app);
}
final Class<StoreEditPanel> componentClass = panelInfo.getComponentClass();
final Constructor<StoreEditPanel> constructor;
try {
constructor = componentClass.getConstructor(String.class, Form.class);
} catch (SecurityException e) {
throw e;
} catch (NoSuchMethodException e) {
throw new RuntimeException(componentClass.getName()
+ " does not provide the required constructor");
}
final StoreEditPanel storeEditPanel;
try {
storeEditPanel = constructor.newInstance(componentId, editForm);
} catch (IllegalArgumentException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException("Cannot instantiate extension point contributor "
+ componentClass.getName(), e);
}
return storeEditPanel;
}
private static DataStorePanelInfo getDefaultPanelInfo(StoreInfo storeInfo,
GeoServerApplication app) {
final List<DataStorePanelInfo> providers = app.getBeansOfType(DataStorePanelInfo.class);
DataStorePanelInfo panelInfo = null;
for (DataStorePanelInfo provider : providers) {
if (storeInfo instanceof DataStoreInfo && "defaultVector".equals(provider.getId())) {
panelInfo = provider;
break;
} else if (storeInfo instanceof CoverageStoreInfo
&& "defaultRaster".equals(provider.getId())) {
panelInfo = provider;
break;
}
}
if (panelInfo == null) {
if (storeInfo instanceof DataStoreInfo) {
throw new IllegalStateException("Bean of type DataStorePanelInfo named "
+ "'defaultDataStorePanel' not provided by application context");
} else if (storeInfo instanceof CoverageStoreInfo) {
throw new IllegalStateException("Bean of type DataStorePanelInfo named "
+ "'defaultCoverageStorePanel' not provided by application context");
} else {
throw new IllegalArgumentException("Unknown store type: "
+ storeInfo.getClass().getName());
}
}
if (panelInfo.getComponentClass() == null) {
throw new IllegalStateException("Default DataStorePanelInfo '" + panelInfo.getId()
+ "' does not define a componentClass property");
}
if (panelInfo.getIconBase() == null || panelInfo.getIcon() == null) {
throw new IllegalStateException("Default DataStorePanelInfo '" + panelInfo.getId()
+ "' does not define default icon");
}
return panelInfo;
}
/**
*
* @param storeInfo
* @param app
* @return the extension point descriptor for the given storeInfo, or {@code null} if there's no
* contribution specific for the given storeInfo's type
*/
private static DataStorePanelInfo findPanelInfo(final StoreInfo storeInfo,
final GeoServerApplication app) {
final Catalog catalog = storeInfo.getCatalog();
final ResourcePool resourcePool = catalog.getResourcePool();
Class<?> factoryClass = null;
if (storeInfo instanceof DataStoreInfo) {
DataAccessFactory storeFactory;
try {
storeFactory = resourcePool.getDataStoreFactory((DataStoreInfo) storeInfo);
} catch (IOException e) {
throw new IllegalArgumentException("no factory found for StoreInfo " + storeInfo);
}
if (storeFactory != null) {
factoryClass = storeFactory.getClass();
}
} else if (storeInfo instanceof CoverageStoreInfo) {
AbstractGridFormat gridFormat;
gridFormat = resourcePool.getGridCoverageFormat((CoverageStoreInfo) storeInfo);
if (gridFormat != null) {
factoryClass = gridFormat.getClass();
}
} else {
throw new IllegalArgumentException("Unknown store type: "
+ storeInfo.getClass().getName());
}
if (factoryClass == null) {
throw new IllegalArgumentException("Can't locate the factory for the store");
}
final List<DataStorePanelInfo> providers = app.getBeansOfType(DataStorePanelInfo.class);
DataStorePanelInfo panelInfo = null;
for (DataStorePanelInfo provider : providers) {
Class<?> providerFactoryClass = provider.getFactoryClass();
if (factoryClass.equals(providerFactoryClass)) {
panelInfo = provider;
break;
}
}
return panelInfo;
}
}