/* (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.gwc.web.layer;
import static org.geoserver.gwc.web.layer.CachedLayerProvider.ACTIONS;
import static org.geoserver.gwc.web.layer.CachedLayerProvider.BLOBSTORE;
import static org.geoserver.gwc.web.layer.CachedLayerProvider.ENABLED;
import static org.geoserver.gwc.web.layer.CachedLayerProvider.NAME;
import static org.geoserver.gwc.web.layer.CachedLayerProvider.PREVIEW_LINKS;
import static org.geoserver.gwc.web.layer.CachedLayerProvider.QUOTA_LIMIT;
import static org.geoserver.gwc.web.layer.CachedLayerProvider.QUOTA_USAGE;
import static org.geoserver.gwc.web.layer.CachedLayerProvider.TYPE;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.apache.wicket.AttributeModifier;
import org.apache.wicket.Component;
import org.apache.wicket.request.resource.PackageResourceReference;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.behavior.AttributeAppender;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.image.Image;
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
import org.apache.wicket.markup.html.link.ExternalLink;
import org.apache.wicket.markup.html.panel.Fragment;
import org.apache.wicket.markup.repeater.RepeatingView;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.ResourceModel;
import org.apache.wicket.model.StringResourceModel;
import org.geoserver.gwc.GWC;
import org.geoserver.gwc.layer.GeoServerTileLayer;
import org.geoserver.gwc.web.GWCIconFactory;
import org.geoserver.ows.util.ResponseUtils;
import org.geoserver.web.GeoServerSecuredPage;
import org.geoserver.web.wicket.GeoServerDataProvider.Property;
import org.geoserver.web.wicket.GeoServerDialog;
import org.geoserver.web.wicket.GeoServerTablePanel;
import org.geoserver.web.wicket.ParamResourceModel;
import org.geoserver.web.wicket.SimpleAjaxLink;
import org.geotools.image.io.ImageIOExt;
import org.geowebcache.diskquota.storage.Quota;
import org.geowebcache.layer.TileLayer;
import org.geowebcache.mime.MimeType;
/**
* @author groldan
* @see GWC#removeTileLayers(List)
*/
public class CachedLayersPage extends GeoServerSecuredPage {
private static final long serialVersionUID = -6795610175856538774L;
private CachedLayerProvider provider = new CachedLayerProvider();
private GeoServerTablePanel<TileLayer> table;
private GeoServerDialog dialog;
private CachedLayerSelectionRemovalLink removal;
public CachedLayersPage() {
table = new GeoServerTablePanel<TileLayer>("table", provider, true) {
private static final long serialVersionUID = 1L;
@SuppressWarnings({ "unchecked" })
@Override
protected Component getComponentForProperty(String id, IModel<TileLayer> itemModel,
Property<TileLayer> property) {
if (property == TYPE) {
Fragment f = new Fragment(id, "iconFragment", CachedLayersPage.this);
PackageResourceReference layerIcon;
TileLayer layer = (TileLayer) itemModel.getObject();
layerIcon = (PackageResourceReference) property.getPropertyValue(layer);
f.add(new Image("layerIcon", layerIcon));
return f;
} else if (property == NAME) {
return nameLink(id, itemModel);
} else if (property == QUOTA_LIMIT) {
IModel<Quota> quotaLimitModel = (IModel<Quota>) property.getModel(itemModel);
return quotaLink(id, quotaLimitModel);
} else if (property == QUOTA_USAGE) {
IModel<Quota> quotaUsageModel = (IModel<Quota>) property.getModel(itemModel);
return quotaLink(id, quotaUsageModel);
} else if (property == ENABLED) {
TileLayer layerInfo = (TileLayer) itemModel.getObject();
boolean enabled = layerInfo.isEnabled();
PackageResourceReference icon;
if (enabled) {
icon = GWCIconFactory.getEnabledIcon();
} else {
icon = GWCIconFactory.getDisabledIcon();
}
Fragment f = new Fragment(id, "iconFragment", CachedLayersPage.this);
f.add(new Image("layerIcon", icon));
return f;
} else if (property == PREVIEW_LINKS) {
return previewLinks(id, itemModel);
} else if (property == ACTIONS) {
return actionsLinks(id, itemModel);
} else if (property == BLOBSTORE) {
return null;
}
throw new IllegalArgumentException("Don't know a property named "
+ property.getName());
}
@Override
protected void onSelectionUpdate(AjaxRequestTarget target) {
removal.setEnabled(table.getSelection().size() > 0);
target.add(removal);
}
};
table.setOutputMarkupId(true);
add(table);
// the confirm dialog
add(dialog = new GeoServerDialog("dialog"));
dialog.setInitialWidth(360);
dialog.setInitialHeight(180);
setHeaderPanel(headerPanel());
Long imageIOFileCachingThreshold = ImageIOExt.getFilesystemThreshold();
if (null == imageIOFileCachingThreshold || 0L >= imageIOFileCachingThreshold.longValue()) {
String warningMsg = new ResourceModel("GWC.ImageIOFileCachingThresholdUnsetWarning")
.getObject();
super.warn(warningMsg);
}
}
private Component quotaLink(String id, IModel<Quota> quotaModel) {
Quota quota = quotaModel.getObject();
String formattedQuota;
if (null == quota) {
formattedQuota = new ResourceModel("CachedLayersPage.quotaLimitNotSet").getObject();
} else {
formattedQuota = quota.toNiceString();
}
return new Label(id, formattedQuota);
}
private Component nameLink(String id, IModel<TileLayer> itemModel) {
Component link;
final TileLayer layer = itemModel.getObject();
final String layerName = layer.getName();
if (layer instanceof GeoServerTileLayer) {
link = new ConfigureCachedLayerAjaxLink(id, itemModel, CachedLayersPage.class);
} else {
link = new Label(id, layerName);
}
return link;
}
private Component actionsLinks(String id, IModel<TileLayer> tileLayerNameModel) {
final String name = tileLayerNameModel.getObject().getName();
final String href = ResponseUtils.baseURL(getGeoServerApplication().servletRequest())
+ "gwc/rest/seed/" + name;
// openlayers preview
Fragment f = new Fragment(id, "actionsFragment", CachedLayersPage.this);
f.add(new ExternalLink("seedLink", href, new ResourceModel("CachedLayersPage.seed")
.getObject()));
f.add(truncateLink("truncateLink", tileLayerNameModel));
return f;
}
private SimpleAjaxLink<String> truncateLink(final String id,
IModel<TileLayer> tileLayerNameModel) {
String layerName = tileLayerNameModel.getObject().getName();
IModel<String> model = new Model<String>(layerName);
IModel<String> labelModel = new ResourceModel("truncate");
SimpleAjaxLink<String> link = new SimpleAjaxLink<String>(id, model, labelModel) {
private static final long serialVersionUID = 1L;
@Override
protected void onClick(AjaxRequestTarget target) {
dialog.setTitle(new ParamResourceModel("confirmTruncateTitle",
CachedLayersPage.this));
dialog.setDefaultModel(getDefaultModel());
dialog.showOkCancel(target, new GeoServerDialog.DialogDelegate() {
private static final long serialVersionUID = 1L;
@Override
protected Component getContents(final String id) {
final String layerName = getDefaultModelObjectAsString();
// show a confirmation panel for all the objects we have to remove
final GWC gwcFacade = GWC.get();
Quota usedQuota = gwcFacade.getUsedQuota(layerName);
if (usedQuota == null) {
usedQuota = new Quota();
}
final String usedQuotaStr = usedQuota.toNiceString();
IModel<String> model = new ParamResourceModel(
"CachedLayersPage.confirmTruncateMessage", CachedLayersPage.this,
layerName, usedQuotaStr);
Label confirmLabel = new Label(id, model);
confirmLabel.setEscapeModelStrings(false);// allow some html inside, like
// <b></b>, etc
return confirmLabel;
}
@Override
protected boolean onSubmit(final AjaxRequestTarget target,
final Component contents) {
final String layerName = getDefaultModelObjectAsString();
GWC facade = GWC.get();
facade.truncate(layerName);
return true;
}
@Override
public void onClose(final AjaxRequestTarget target) {
target.add(table);
}
});
}
};
return link;
}
private Component previewLinks(String id, IModel<TileLayer> tileLayerModel) {
final TileLayer layer = tileLayerModel.getObject();
if (!layer.isEnabled()) {
return new Label(id, new ResourceModel("previewDisabled"));
}
final Set<String> gridSubsets = new TreeSet<String>(layer.getGridSubsets());
final List<MimeType> mimeTypes = new ArrayList<MimeType>(layer.getMimeTypes());
Collections.sort(mimeTypes, new Comparator<MimeType>() {
@Override
public int compare(MimeType o1, MimeType o2) {
return o1.getFormat().compareTo(o2.getFormat());
}
});
Fragment f = new Fragment(id, "menuFragment", CachedLayersPage.this);
WebMarkupContainer menu = new WebMarkupContainer("menu");
RepeatingView previewLinks = new RepeatingView("previewLink");
int i = 0;
for (String gridSetId : gridSubsets) {
for (MimeType mimeType : mimeTypes) {
String label = gridSetId + " / " + mimeType.getFileExtension();
// build option with text and value
Label format = new Label(String.valueOf(i++), label);
String value = "gridSet=" + gridSetId + "&format=" + mimeType.getFormat();
format.add(new AttributeModifier("value", new Model<String>(value)));
previewLinks.add(format);
}
}
menu.add(previewLinks);
// build the wms request, redirect to it in a new window, reset the selection
String demoUrl = "'" + ResponseUtils.baseURL(getGeoServerApplication().servletRequest())
+ "gwc/demo/" + layer.getName()
+ "?' + this.options[this.selectedIndex].value";
menu.add(new AttributeAppender("onchange", new Model<String>("window.open(" + demoUrl
+ ");this.selectedIndex=0"), ";"));
f.add(menu);
return f;
}
protected Component headerPanel() {
Fragment header = new Fragment(HEADER_PANEL, "header", this);
// the add button
header.add(new BookmarkablePageLink<String>("addNew", NewCachedLayerPage.class));
// the removal button
header.add(removal = new CachedLayerSelectionRemovalLink("removeSelected"));
removal.setOutputMarkupId(true);
removal.setEnabled(false);
return header;
}
private class CachedLayerSelectionRemovalLink extends AjaxLink<TileLayer> {
private static final long serialVersionUID = 1L;
public CachedLayerSelectionRemovalLink(String string) {
super(string);
}
@Override
public void onClick(final AjaxRequestTarget target) {
List<TileLayer> selection = CachedLayersPage.this.table.getSelection();
if (selection.isEmpty()) {
return;
}
final List<String> selectedNames = new ArrayList<String>();
for (TileLayer layer : selection) {
selectedNames.add(layer.getName());
}
dialog.setTitle(new ParamResourceModel("confirmRemoval", CachedLayersPage.this));
// if there is something to cancel, let's warn the user about what
// could go wrong, and if the user accepts, let's delete what's needed
dialog.showOkCancel(target, new GeoServerDialog.DialogDelegate() {
private static final long serialVersionUID = 1L;
@Override
protected Component getContents(final String id) {
// show a confirmation panel for all the objects we have to remove
final GWC gwcFacade = GWC.get();
Quota totalQuota = new Quota();
for (String layerName : selectedNames) {
Quota usedQuota = gwcFacade.getUsedQuota(layerName);
if (usedQuota != null) {
totalQuota.add(usedQuota);
}
}
final String usedQuotaStr = totalQuota.toNiceString();
final Integer selectedLayerCount = selectedNames.size();
IModel<String> model = new StringResourceModel
("CachedLayersPage.confirmSelectionRemoval",
CachedLayerSelectionRemovalLink.this).setParameters(new Object[] {
selectedLayerCount.toString(), usedQuotaStr });
Label confirmLabel = new Label(id, model);
confirmLabel.setEscapeModelStrings(false);// allow some html inside, like
// <b></b>, etc
return confirmLabel;
}
@Override
protected boolean onSubmit(final AjaxRequestTarget target, final Component contents) {
GWC facade = GWC.get();
facade.removeTileLayers(selectedNames);
table.clearSelection();
return true;
}
@Override
public void onClose(final AjaxRequestTarget target) {
// if the selection has been cleared out it's sign a deletion
// occurred, so refresh the table
List<TileLayer> selection = table.getSelection();
if (selection.isEmpty()) {
setEnabled(false);
target.add(CachedLayerSelectionRemovalLink.this);
target.add(table);
}
}
});
}
}
}