/* Copyright (c) 2001 - 2007 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.workspace; import java.io.Serializable; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.logging.Logger; import org.apache.wicket.AttributeModifier; import org.apache.wicket.Component; import org.apache.wicket.Page; import org.apache.wicket.PageParameters; import org.apache.wicket.ResourceReference; import org.apache.wicket.WicketRuntimeException; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.markup.html.AjaxLink; import org.apache.wicket.ajax.markup.html.form.AjaxCheckBox; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.CheckBox; import org.apache.wicket.markup.html.form.ChoiceRenderer; import org.apache.wicket.markup.html.form.DropDownChoice; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.form.FormComponentPanel; import org.apache.wicket.markup.html.form.SubmitLink; import org.apache.wicket.markup.html.form.TextField; import org.apache.wicket.markup.html.image.Image; import org.apache.wicket.markup.html.link.BookmarkablePageLink; import org.apache.wicket.markup.html.link.Link; import org.apache.wicket.markup.html.list.ListItem; import org.apache.wicket.markup.html.list.ListView; import org.apache.wicket.markup.html.panel.Panel; import org.apache.wicket.model.CompoundPropertyModel; import org.apache.wicket.model.IModel; import org.apache.wicket.model.LoadableDetachableModel; import org.apache.wicket.model.Model; import org.apache.wicket.model.PropertyModel; import org.apache.wicket.model.StringResourceModel; import org.geoserver.catalog.Catalog; import org.geoserver.catalog.NamespaceInfo; import org.geoserver.catalog.WorkspaceInfo; import org.geoserver.config.GeoServer; import org.geoserver.config.ServiceInfo; import org.geoserver.config.impl.ServiceInfoImpl; import org.geoserver.ows.util.OwsUtils; import org.geoserver.web.GeoServerApplication; import org.geoserver.web.GeoServerBasePage; import org.geoserver.web.GeoServerSecuredPage; import org.geoserver.web.MenuPageInfo; import org.geoserver.web.data.namespace.NamespaceDetachableModel; import org.geoserver.web.services.BaseServiceAdminPage; import org.geoserver.web.services.ServiceMenuPageInfo; import org.geoserver.web.wicket.GeoServerDialog; import org.geoserver.web.wicket.ParamResourceModel; import org.geoserver.web.wicket.URIValidator; import org.geoserver.web.wicket.XMLNameValidator; import org.geotools.util.logging.Logging; /** * Allows editing a specific workspace */ @SuppressWarnings("serial") public class WorkspaceEditPage extends GeoServerSecuredPage { private static final Logger LOGGER = Logging.getLogger("org.geoserver.web.data.workspace"); IModel wsModel; IModel nsModel; boolean defaultWs; ServicesPanel servicesPanel; GeoServerDialog dialog; /** * Uses a "name" parameter to locate the workspace * @param parameters */ public WorkspaceEditPage(PageParameters parameters) { String wsName = parameters.getString("name"); WorkspaceInfo wsi = getCatalog().getWorkspaceByName(wsName); if(wsi == null) { error(new ParamResourceModel("WorkspaceEditPage.notFound", this, wsName).getString()); setResponsePage(WorkspacePage.class); return; } init(wsi); } public WorkspaceEditPage(WorkspaceInfo ws) { init(ws); } private void init(WorkspaceInfo ws) { defaultWs = ws.getId().equals(getCatalog().getDefaultWorkspace().getId()); wsModel = new WorkspaceDetachableModel( ws ); NamespaceInfo ns = getCatalog().getNamespaceByPrefix( ws.getName() ); nsModel = new NamespaceDetachableModel(ns); Form form = new Form( "form", new CompoundPropertyModel( nsModel ) ) { protected void onSubmit() { try { saveWorkspace(); } catch (RuntimeException e) { error(e.getMessage()); } } }; add(form); TextField name = new TextField("name", new PropertyModel(wsModel, "name")); name.setRequired(true); name.add(new XMLNameValidator()); form.add(name); TextField uri = new TextField("uri", new PropertyModel(nsModel, "uRI"), String.class); uri.setRequired(true); uri.add(new URIValidator()); form.add(uri); CheckBox defaultChk = new CheckBox("default", new PropertyModel(this, "defaultWs")); form.add(defaultChk); //stores // StorePanel storePanel = new StorePanel("storeTable", new StoreProvider(ws), false); // form.add(storePanel); //local services form.add(servicesPanel = new ServicesPanel("services", wsModel)); form.add(new AjaxLink("servicesHelp") { @Override public void onClick(AjaxRequestTarget target) { dialog.showInfo(target, new StringResourceModel("servicesHelp.title",WorkspaceEditPage.this, null), new StringResourceModel("servicesHelp.message.1",WorkspaceEditPage.this, null), new StringResourceModel("servicesHelp.message.2",WorkspaceEditPage.this, null)); } }); SubmitLink submit = new SubmitLink("save"); form.add(submit); form.setDefaultButton(submit); form.add(new BookmarkablePageLink("cancel", WorkspacePage.class)); add(dialog = new GeoServerDialog("dialog")); } private void saveWorkspace() { final Catalog catalog = getCatalog(); NamespaceInfo namespaceInfo = (NamespaceInfo) nsModel.getObject(); WorkspaceInfo workspaceInfo = (WorkspaceInfo) wsModel.getObject(); // sync up workspace name with namespace prefix, temp measure until the two become separate namespaceInfo.setPrefix(workspaceInfo.getName()); // this will ensure all datastore namespaces are updated when the workspace is modified catalog.save(workspaceInfo); catalog.save(namespaceInfo); if(defaultWs) { catalog.setDefaultWorkspace(workspaceInfo); } //persist/depersist any services configured local to this workspace GeoServer geoServer = getGeoServer(); for (Service s : servicesPanel.services) { if (s.enabled) { if (s.model instanceof ExistingServiceModel) { //nothing to do, service has already been added continue; } geoServer.add(s.model.getObject()); } else { //remove if necessary if (s.model instanceof ExistingServiceModel) { //means they are removing an existing service, look it up and remove geoServer.remove(s.model.getObject()); } } } setResponsePage(WorkspacePage.class); } /* * Data object to hold onto transient services, and maintain state of selected services for * the workspace. */ static class Service implements Serializable { /** track selection */ Boolean enabled; /** the admin page for the service */ ServiceMenuPageInfo adminPage; /** created service, not yet added to configuration */ IModel<ServiceInfo> model; } static class NewServiceModel extends Model<ServiceInfo> { IModel<WorkspaceInfo> wsModel; Class<ServiceInfo> serviceClass; ServiceInfo service; NewServiceModel(IModel<WorkspaceInfo> wsModel, Class<ServiceInfo> serviceClass) { this.wsModel = wsModel; this.serviceClass = serviceClass; } @Override public ServiceInfo getObject() { if (service == null) { service = create(); } return service; } ServiceInfo create() { //create it GeoServer gs = GeoServerApplication.get().getGeoServer(); ServiceInfo newService = gs.getFactory().create(serviceClass); //initialize from global service ServiceInfo global = gs.getService(serviceClass); OwsUtils.copy(global,newService, serviceClass); newService.setWorkspace(wsModel.getObject()); //hack, but need id to be null so its considered unattached ((ServiceInfoImpl)newService).setId(null); return newService; } } static class ExistingServiceModel extends LoadableDetachableModel<ServiceInfo> { IModel<WorkspaceInfo> wsModel; Class<ServiceInfo> serviceClass; ExistingServiceModel(IModel<WorkspaceInfo> wsModel, Class<ServiceInfo> serviceClass) { this.wsModel = wsModel; this.serviceClass = serviceClass; } @Override protected ServiceInfo load() { return GeoServerApplication.get().getGeoServer().getService(wsModel.getObject(), serviceClass); } } class ServicesPanel extends FormComponentPanel { List<Service> services; public ServicesPanel(String id, final IModel<WorkspaceInfo> wsModel) { super(id, new Model()); services = services(wsModel); ListView<Service> serviceList = new ListView<Service>("services", services) { @Override protected void populateItem(ListItem<Service> item) { Service service = item.getModelObject(); final Link<Service> link = new Link<Service>("link", new Model(service)) { @Override public void onClick() { Service s = getModelObject(); Page page = null; if (s.model instanceof ExistingServiceModel) { //service that has already been added, PageParameters pp = new PageParameters("workspace=" + wsModel.getObject().getName()); try { page = s.adminPage.getComponentClass() .getConstructor(PageParameters.class).newInstance(pp); } catch (Exception e) { throw new WicketRuntimeException(e); } } else { //service that has yet to be added try { page = s.adminPage.getComponentClass().getConstructor( s.adminPage.getServiceClass()).newInstance(s.model.getObject()); } catch (Exception e) { throw new WicketRuntimeException(e); } } ((BaseServiceAdminPage)page).responsePage(WorkspaceEditPage.this); setResponsePage(page); } }; link.setOutputMarkupId(true); link.setEnabled(service.enabled); AjaxCheckBox enabled = new AjaxCheckBox("enabled", new PropertyModel<Boolean>(service, "enabled")) { @Override protected void onUpdate(AjaxRequestTarget target) { link.setEnabled(getModelObject()); target.addComponent(link); } }; item.add(enabled); ServiceMenuPageInfo info = service.adminPage; link.add(new AttributeModifier("title", true, new StringResourceModel(info.getDescriptionKey(), (Component) null, null))); link.add(new Label("link.label", new StringResourceModel(info.getTitleKey(), (Component) null, null))); Image image; if(info.getIcon() != null) { image = new Image("link.icon", new ResourceReference(info.getComponentClass(), info.getIcon())); } else { image = new Image("link.icon", new ResourceReference(GeoServerBasePage.class, "img/icons/silk/wrench.png")); } image.add(new AttributeModifier("alt", true, new ParamResourceModel(info.getTitleKey(), null))); link.add(image); item.add(link); } }; add(serviceList); } List<Service> services(IModel<WorkspaceInfo> wsModel) { List<Service> services = new ArrayList(); for (ServiceMenuPageInfo page : getGeoServerApplication().getBeansOfType(ServiceMenuPageInfo.class)) { Service service = new Service(); service.adminPage = page; service.enabled = getGeoServer().getService(wsModel.getObject(), page.getServiceClass()) != null; //if service is disabled, create a placeholder model to hold a newly created one, // otherwise create a live model to the existing service Class<ServiceInfo> serviceClass = (Class<ServiceInfo>) page.getServiceClass(); service.model = !service.enabled ? new NewServiceModel(wsModel, serviceClass) : new ExistingServiceModel(wsModel, serviceClass); services.add(service); } return services; } } }