diff --git a/ccm-core/src/main/java/org/libreccm/pagemodel/rs/Components.java b/ccm-core/src/main/java/org/libreccm/pagemodel/rs/Components.java index 25a250cee..a553018c4 100644 --- a/ccm-core/src/main/java/org/libreccm/pagemodel/rs/Components.java +++ b/ccm-core/src/main/java/org/libreccm/pagemodel/rs/Components.java @@ -20,12 +20,23 @@ package org.libreccm.pagemodel.rs; import org.libreccm.core.CoreConstants; import org.libreccm.pagemodel.ComponentModel; +import org.libreccm.pagemodel.ComponentModelRepository; import org.libreccm.pagemodel.ContainerModel; +import org.libreccm.pagemodel.ContainerModelManager; import org.libreccm.pagemodel.PageModel; import org.libreccm.security.AuthorizationRequired; import org.libreccm.security.RequiresPrivilege; import org.libreccm.web.CcmApplication; +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Optional; + import javax.enterprise.context.RequestScoped; import javax.inject.Inject; import javax.json.Json; @@ -34,10 +45,14 @@ import javax.json.JsonArrayBuilder; import javax.json.JsonObject; import javax.json.JsonObjectBuilder; import javax.transaction.Transactional; +import javax.ws.rs.BadRequestException; +import javax.ws.rs.Consumes; import javax.ws.rs.GET; +import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; /** * @@ -47,6 +62,12 @@ import javax.ws.rs.Produces; @Path("/") public class Components { + @Inject + private ComponentModelRepository componentRepo; + + @Inject + private ContainerModelManager containerManager; + @Inject private PageModelsController controller; @@ -104,6 +125,53 @@ public class Components { return mapComponentModelToJson(component); } + @PUT + @Path(PageModelsApp.COMPONENT_PATH) + @Consumes("application/json; charset=utf-8") + @Produces("application/json; charset=utf-8") + @Transactional(Transactional.TxType.REQUIRED) + @AuthorizationRequired + @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) + public JsonObject putComponent( + @PathParam(PageModelsApp.APP_NAME) final String appPath, + @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, + @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey, + @PathParam(PageModelsApp.COMPONENT_KEY) final String componentKey, + final JsonObject componentModelJson) { + + final CcmApplication app = controller.findCcmApplication( + String.format("/%s/", appPath)); + final PageModel pageModel = controller.findPageModel(app, + pageModelName); + final ContainerModel container = controller.findContainer(app, + pageModel, + containerKey); + + final Optional result = container + .getComponents() + .stream() + .filter(c -> c.getKey().equals(componentKey)) + .findAny(); + + final ComponentModel componentModel; + if (result.isPresent()) { + + componentModel = result.get(); + + } else { + + componentModel = createComponentModel(componentModelJson); + componentModel.setKey(componentKey); + containerManager.addComponentModel(container, componentModel); + } + + setComponentPropertiesFromJson(componentModelJson, componentModel); + + componentRepo.save(componentModel); + + return mapComponentModelToJson(componentModel); + } + private JsonObject mapComponentModelToJson( final ComponentModel componentModel) { @@ -133,4 +201,98 @@ public class Components { return objectBuilder.build(); } + private ComponentModel createComponentModel(final JsonObject data) { + + if (!data.containsKey("type")) { + throw new BadRequestException("The JSON data for creating the " + + "component has no value for the type of the component to " + + "create."); + } + + final String type = data.getString("type"); + final Class clazz = findComponentModelClass( + type); + + final ComponentModel componentModel; + try { + componentModel = clazz.getConstructor().newInstance(); + } catch (IllegalAccessException + | InstantiationException + | InvocationTargetException + | NoSuchMethodException ex) { + throw new WebApplicationException(ex); + } + + return componentModel; + } + + @SuppressWarnings("unchecked") + private Class findComponentModelClass( + final String type) { + try { + final Class clazz = Class.forName(type); + + if (clazz.isAssignableFrom(ComponentModel.class)) { + return (Class) clazz; + } else { + throw new BadRequestException(String.format( + "The type \"%s\" is not a subclass of \"%s\".", + type, + ComponentModel.class.getName())); + } + } catch (ClassNotFoundException ex) { + throw new BadRequestException(String.format( + "The component model type \"%s\" " + + "does not exist.", + type)); + } + } + + private void setComponentPropertiesFromJson( + final JsonObject data, + final ComponentModel componentModel) { + + final BeanInfo beanInfo; + try { + beanInfo = Introspector.getBeanInfo(componentModel.getClass()); + } catch (IntrospectionException ex) { + throw new WebApplicationException(ex); + } + + Arrays + .stream(beanInfo.getPropertyDescriptors()) + .forEach( + propertyDesc -> setComponentPropertyFromJson(componentModel, + propertyDesc, + data)); + } + + private void setComponentPropertyFromJson( + final ComponentModel componentModel, + final PropertyDescriptor propertyDesc, + final JsonObject data) { + + // Ignore key and type (handled by other methods). + if ("key".equals(propertyDesc.getName()) + || "type".equals(propertyDesc.getName())) { + + return; + } + + if (data.containsKey(propertyDesc.getName())) { + + final Method writeMethod = propertyDesc.getWriteMethod(); + + if (writeMethod != null) { + try { + writeMethod.invoke(componentModel, + data.getString(propertyDesc.getName())); + } catch (IllegalAccessException + | InvocationTargetException ex) { + throw new WebApplicationException(ex); + } + } + } + } + } diff --git a/ccm-core/src/main/java/org/libreccm/pagemodel/rs/Containers.java b/ccm-core/src/main/java/org/libreccm/pagemodel/rs/Containers.java index f44911dfc..4373fa3ec 100644 --- a/ccm-core/src/main/java/org/libreccm/pagemodel/rs/Containers.java +++ b/ccm-core/src/main/java/org/libreccm/pagemodel/rs/Containers.java @@ -20,11 +20,16 @@ package org.libreccm.pagemodel.rs; import org.libreccm.core.CoreConstants; import org.libreccm.pagemodel.ContainerModel; +import org.libreccm.pagemodel.ContainerModelRepository; import org.libreccm.pagemodel.PageModel; +import org.libreccm.pagemodel.PageModelManager; +import org.libreccm.pagemodel.PageModelRepository; import org.libreccm.security.AuthorizationRequired; import org.libreccm.security.RequiresPrivilege; import org.libreccm.web.CcmApplication; +import java.util.Optional; + import javax.enterprise.context.RequestScoped; import javax.inject.Inject; import javax.json.Json; @@ -32,7 +37,10 @@ import javax.json.JsonArray; import javax.json.JsonArrayBuilder; import javax.json.JsonObject; import javax.transaction.Transactional; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; import javax.ws.rs.GET; +import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; @@ -48,6 +56,15 @@ public class Containers { @Inject private PageModelsController controller; + @Inject + private ContainerModelRepository containerModelRepo; + + @Inject + private PageModelManager pageModelManager; + + @Inject + private PageModelRepository pageModelRepo; + @GET @Path(PageModelsApp.CONTAINERS_PATH) @Produces("application/json; charset=utf-8") @@ -98,6 +115,72 @@ public class Containers { return mapContainerModelToJson(container); } + @PUT + @Path(PageModelsApp.CONTAINER_PATH) + @Consumes("application/json; charset=utf-8") + @Produces("application/json; charset=utf-8") + @Transactional(Transactional.TxType.REQUIRED) + @AuthorizationRequired + @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) + public JsonObject putContainer( + @PathParam(PageModelsApp.APP_NAME) final String appPath, + @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, + @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey, + final JsonObject containerModelJson) { + + final CcmApplication app = controller.findCcmApplication( + String.format("/%s/", appPath)); + + final PageModel pageModel = controller.findPageModel(app, + pageModelName); + + final Optional result = pageModel + .getContainers() + .stream() + .filter(model -> model.getKey().equals(containerKey)) + .findAny(); + + final ContainerModel containerModel; + if (result.isPresent()) { + + containerModel = result.get(); + + result.get().setKey(containerKey); + containerModelRepo.save(result.get()); + } else { + + containerModel = new ContainerModel(); + containerModel.setKey(containerKey); + + pageModelManager.addContainerModel(pageModel, containerModel); + } + + return mapContainerModelToJson(containerModel); + } + + @DELETE + @Path(PageModelsApp.CONTAINER_PATH) + @Transactional(Transactional.TxType.REQUIRED) + @AuthorizationRequired + @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) + public void deleteContainer( + @PathParam(PageModelsApp.APP_NAME) final String appPath, + @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, + @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey) { + + final CcmApplication app = controller.findCcmApplication( + String.format("/%s/", appPath)); + + final PageModel pageModel = controller.findPageModel(app, + pageModelName); + + final ContainerModel container = controller.findContainer(app, + pageModel, + containerKey); + + pageModelManager.removeContainerModel(pageModel, container); + } + private JsonObject mapContainerModelToJson( final ContainerModel containerModel) { diff --git a/ccm-core/src/main/java/org/libreccm/pagemodel/rs/PageModels.java b/ccm-core/src/main/java/org/libreccm/pagemodel/rs/PageModels.java index a70be7734..20b19a52e 100644 --- a/ccm-core/src/main/java/org/libreccm/pagemodel/rs/PageModels.java +++ b/ccm-core/src/main/java/org/libreccm/pagemodel/rs/PageModels.java @@ -36,6 +36,7 @@ import javax.json.JsonArrayBuilder; import javax.json.JsonObject; import javax.transaction.Transactional; import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.NotFoundException; import javax.ws.rs.PUT; @@ -145,12 +146,28 @@ public class PageModels { pageModel.setApplication(app); } pageModel.setName(pageModelName); - + controller.savePageModel(pageModel); - + return mapPageModelToJson(controller.findPageModel(app, pageModelName)); } + @DELETE + @Path(PageModelsApp.PAGE_MODEL_PATH) + @Transactional(Transactional.TxType.REQUIRED) + @AuthorizationRequired + @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) + public void deletePageModel( + @PathParam(PageModelsApp.APP_NAME) final String appPath, + @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName) { + + final CcmApplication app = controller + .findCcmApplication(String.format("/%s/", appPath)); + final PageModel pageModel = controller.findPageModel(app, + pageModelName); + pageModelRepo.delete(pageModel); + } + private JsonObject mapPageModelToJson(final PageModel pageModel) { return Json diff --git a/ccm-core/src/main/java/org/libreccm/pagemodel/rs/PageModelsController.java b/ccm-core/src/main/java/org/libreccm/pagemodel/rs/PageModelsController.java index be1cb952b..2b43b90ed 100644 --- a/ccm-core/src/main/java/org/libreccm/pagemodel/rs/PageModelsController.java +++ b/ccm-core/src/main/java/org/libreccm/pagemodel/rs/PageModelsController.java @@ -98,6 +98,8 @@ class PageModelsController { containerKey))); } + + @Transactional(Transactional.TxType.REQUIRED) protected boolean existsPageModel(final CcmApplication app, final String pageModelName) {