/* * * This is a simple Content Management System (CMS) * Copyright (C) 2010 Imran M Yousuf (imyousuf@smartitengineering.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.smartitengineering.cms.ws.resources.content; import com.smartitengineering.cms.api.content.CollectionFieldValue; import com.smartitengineering.cms.api.content.Content; import com.smartitengineering.cms.api.content.ContentFieldValue; import com.smartitengineering.cms.api.content.ContentId; import com.smartitengineering.cms.api.content.Field; import com.smartitengineering.cms.api.content.FieldValue; import com.smartitengineering.cms.api.content.MutableCollectionFieldValue; import com.smartitengineering.cms.api.content.MutableCompositeFieldValue; import com.smartitengineering.cms.api.content.MutableContentFieldValue; import com.smartitengineering.cms.api.content.MutableField; import com.smartitengineering.cms.api.factory.SmartContentAPI; import com.smartitengineering.cms.api.factory.content.WriteableContent; import com.smartitengineering.cms.api.type.CollectionDataType; import com.smartitengineering.cms.api.type.CompositeDataType; import com.smartitengineering.cms.api.type.ContentStatus; import com.smartitengineering.cms.api.type.ContentType; import com.smartitengineering.cms.api.type.DataType; import com.smartitengineering.cms.api.type.FieldDef; import com.smartitengineering.cms.api.type.FieldValueType; import com.smartitengineering.cms.api.type.OtherDataType; import com.smartitengineering.cms.api.type.RepresentationDef; import com.smartitengineering.cms.api.type.VariationDef; import com.smartitengineering.cms.ws.common.domains.CollectionFieldValueImpl; import com.smartitengineering.cms.ws.common.domains.CompositeFieldValue; import com.smartitengineering.cms.ws.common.domains.CompositeFieldValueImpl; import com.smartitengineering.cms.ws.common.domains.ContentImpl; import com.smartitengineering.cms.ws.common.domains.FieldImpl; import com.smartitengineering.cms.ws.common.domains.FieldValueImpl; import com.smartitengineering.cms.ws.common.domains.OtherFieldValueImpl; import com.smartitengineering.cms.ws.common.utils.SimpleFeedExtensions; import com.smartitengineering.cms.ws.resources.ResourcesConfig; import com.smartitengineering.cms.ws.resources.type.ContentTypeResource; import com.smartitengineering.util.bean.adapter.AbstractAdapterHelper; import com.smartitengineering.util.bean.adapter.GenericAdapter; import com.smartitengineering.util.bean.adapter.GenericAdapterImpl; import com.smartitengineering.util.rest.atom.server.AbstractResource; import com.smartitengineering.util.rest.server.ServerResourceInjectables; import com.sun.jersey.api.container.ContainerException; import com.sun.jersey.api.core.ResourceContext; import com.sun.jersey.multipart.FormDataBodyPart; import com.sun.jersey.multipart.FormDataMultiPart; import java.io.IOException; import java.io.StringWriter; import java.net.URI; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.HeaderParam; import javax.ws.rs.POST; 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; import javax.ws.rs.core.CacheControl; import javax.ws.rs.core.EntityTag; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.ResponseBuilder; import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriBuilderException; import org.apache.abdera.model.Feed; import org.apache.abdera.model.Link; import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.StringUtils; import org.codehaus.jackson.map.ObjectMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * * @author imyousuf */ public class ContentResource extends AbstractResource { private final Content content; private final ContentId contentId; private final EntityTag tag; private final boolean importMode; private final static transient Logger LOGGER = LoggerFactory.getLogger(ContentResource.class); protected final GenericAdapter<Content, com.smartitengineering.cms.ws.common.domains.Content> adapter; public static final String PATH_TO_REP = "r/{repName}"; public static final String PATH_TO_FIELD = "f/{fieldName}"; public static final String PATH_TO_REINDEX = "reindex"; public ContentResource(ServerResourceInjectables injectables, ContentId contentId) { this(injectables, contentId, false); } public ContentResource(ServerResourceInjectables injectables, ContentId contentId, boolean importMode) { super(injectables); this.importMode = importMode; if (contentId == null) { throw new WebApplicationException(Response.Status.BAD_REQUEST); } this.contentId = contentId; if (LOGGER.isDebugEnabled()) { LOGGER.debug("Content ID " + contentId); } if (contentId.getId() != null && contentId.getId().length > 0) { //An existing content this.content = SmartContentAPI.getInstance().getContentLoader().loadContent(contentId); } else { //New content is being created this.content = null; } if (content != null) { tag = new EntityTag(content.getEntityTagValue()); } else { tag = null; } GenericAdapterImpl adapterImpl = new GenericAdapterImpl<Content, com.smartitengineering.cms.ws.common.domains.Content>(); adapterImpl.setHelper(new ContentAdapterHelper(injectables, importMode)); adapter = adapterImpl; } @Path(PATH_TO_FIELD) public FieldResource getFieldResource(@PathParam("fieldName") String fieldName) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Trying to get field resource with name " + fieldName); } FieldDef fieldDef = content.getContentDefinition().getFieldDefs().get(fieldName); FieldResource resource = new FieldResource(getInjectables(), content, fieldDef, tag); return resource; } @Path(PATH_TO_REP) public RepresentationResource getRepresentationResource(@PathParam("repName") String repName) { return new RepresentationResource(getInjectables(), repName, content); } @Path(PATH_TO_REINDEX) public ContentReIndexResource reindex() { ContentReIndexResource resource = new ContentReIndexResource(getInjectables()); resource.setContentId(contentId); return resource; } @GET @Produces(MediaType.APPLICATION_JSON) public Response get() { if (content == null) { throw new WebApplicationException(Response.Status.NOT_FOUND); } ResponseBuilder builder = getContext().getRequest().evaluatePreconditions(content.getLastModifiedDate(), tag); if (builder == null) { builder = Response.ok(adapter.convert(getContent())); buildCommonContentResponseFields(builder); } return builder.build(); } @GET @Produces(MediaType.APPLICATION_ATOM_XML) public Response getAtomFeed() { if (content == null) { throw new WebApplicationException(Response.Status.NOT_FOUND); } ResponseBuilder builder = getContext().getRequest().evaluatePreconditions(content.getLastModifiedDate(), tag); if (builder == null) { final String idStr = content.getContentId().toString(); Feed feed = getFeed(idStr, idStr, content.getLastModifiedDate()); feed.addLink(getLink(getUriInfo().getRequestUri(), Link.REL_ALTERNATE, MediaType.APPLICATION_JSON)); feed.addSimpleExtension(SimpleFeedExtensions.WORKSPACE_NAME_SPACE, content.getContentId().getWorkspaceId(). getGlobalNamespace()); feed.addSimpleExtension(SimpleFeedExtensions.WORKSPACE_NAME, content.getContentId().getWorkspaceId().getName()); feed.addSimpleExtension(SimpleFeedExtensions.CONTENT_ID_IN_WORKSPACAE, org.apache.commons.codec.binary.StringUtils.newStringUtf8(content.getContentId().getId())); Map<String, Field> fields = content.getFields(); final String contentUri = ContentResource.getContentUri(getRelativeURIBuilder(), content.getContentId()). toASCIIString(); final ContentType contentDefinition = content.getContentDefinition(); if (contentDefinition != null && fields != null && !fields.isEmpty()) { final Map<String, FieldDef> fieldDefs = contentDefinition.getFieldDefs(); ObjectMapper objectMapper = new ObjectMapper(); for (Entry<String, Field> field : fields.entrySet()) { final FieldDef def = fieldDefs.get(field.getKey()); if (def != null) { final URI fieldURI = FieldResource.getFieldURI(getRelativeURIBuilder(), content, def); org.apache.abdera.model.Entry entry = getEntry(field.getKey(), field.getKey(), content.getLastModifiedDate(), getLink(fieldURI, Link.REL_ALTERNATE, MediaType.APPLICATION_JSON)); FieldImpl jsonField = new FieldImpl(); ContentResource.getDomainField(getRelativeURIBuilder(), field.getValue(), contentUri, jsonField); StringWriter writer = new StringWriter(); try { objectMapper.writeValue(writer, jsonField); entry.setContent(writer.toString(), MediaType.APPLICATION_JSON); feed.addEntry(entry); } catch (Exception ex) { LOGGER.warn("Error adding content field json", ex); } } } } builder = Response.ok(feed); buildCommonContentResponseFields(builder); } return builder.build(); } protected void buildCommonContentResponseFields(ResponseBuilder builder) { builder.tag(tag); builder.lastModified(getContent().getLastModifiedDate()); CacheControl control = new CacheControl(); control.setMaxAge(ResourcesConfig.getInstance().getContentHttpCacheControlMaxAge()); builder.header(HttpHeaders.VARY, HttpHeaders.ACCEPT); builder.cacheControl(control); } @POST @Consumes(MediaType.MULTIPART_FORM_DATA) public Response post(FormDataMultiPart multiPart) { LOGGER.info("Received POST for content as multipart/form-data"); com.smartitengineering.cms.ws.common.domains.Content contentImpl = parseMultipartFormData(multiPart, getInjectables()); if (LOGGER.isDebugEnabled()) { try { ObjectMapper mapper = new ObjectMapper(); LOGGER.debug("Serialized content impl is " + mapper.writeValueAsString(contentImpl)); } catch (Exception ex) { LOGGER.warn("Could not output info log ", ex); } } return put(contentImpl, this.content == null ? null : new EntityTag("*")); } public static com.smartitengineering.cms.ws.common.domains.Content parseMultipartFormData( FormDataMultiPart multiPart, ServerResourceInjectables injectables) throws WebApplicationException { ContentImpl contentImpl = new ContentImpl(); contentImpl.setContentTypeUri(multiPart.getField("contentTypeUri").getValue()); final FormDataBodyPart field = multiPart.getField("parentContentUri"); if (field != null) { contentImpl.setParentContentUri(field.getValue()); } contentImpl.setStatus(multiPart.getField("status").getValue()); final FormDataBodyPart part = multiPart.getField("private"); contentImpl.setPrivateContent(part == null || org.apache.commons.lang.StringUtils.isBlank(part.getValue()) ? false : (part.getValue().equals("on") ? true : false)); if (org.apache.commons.lang.StringUtils.isNotBlank(contentImpl.getContentTypeUri())) { final ContentType contentType; try { contentType = getContentTypeResource(contentImpl.getContentTypeUri(), injectables).getType(); } catch (Exception ex) { LOGGER.warn("Count not extract content type info!", ex); throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST).build()); } final Map<String, FieldDef> allDefs = contentType.getFieldDefs(); final Collection<com.smartitengineering.cms.ws.common.domains.Field> fields = new ArrayList(); final Map<String, List<FormDataBodyPart>> bodyParts = multiPart.getFields(); formFields(allDefs, bodyParts, fields); contentImpl.getFields().addAll(fields); } return contentImpl; } protected static void formFields(final Map<String, FieldDef> allDefs, final Map<String, List<FormDataBodyPart>> bodyParts, final Collection<com.smartitengineering.cms.ws.common.domains.Field> fields) { for (Entry<String, FieldDef> fieldDef : allDefs.entrySet()) { if (bodyParts != null && !bodyParts.isEmpty()) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Creating field for " + fieldDef.getKey() + " with type " + fieldDef.getValue().getValueDef(). getType()); } FieldImpl fieldImpl = new FieldImpl(); fieldImpl.setName(fieldDef.getKey()); final boolean containsKey = bodyParts.containsKey(fieldDef.getKey()); switch (fieldDef.getValue().getValueDef().getType()) { case COMPOSITE: { boolean hasCompositeValue = false; Map<String, List<FormDataBodyPart>> composites = new LinkedHashMap<String, List<FormDataBodyPart>>(); final String prefix = new StringBuilder(fieldDef.getKey()).append('.').toString(); for (String key : bodyParts.keySet()) { if (key.startsWith(prefix)) { hasCompositeValue = true; composites.put(key.substring(prefix.length()), bodyParts.get(key)); } } if (hasCompositeValue) { Collection<com.smartitengineering.cms.ws.common.domains.Field> composedFields = new ArrayList<com.smartitengineering.cms.ws.common.domains.Field>(); CompositeDataType compositeDataType = (CompositeDataType) fieldDef.getValue().getValueDef(); formFields(compositeDataType.getComposedFieldDefs(), composites, composedFields); CompositeFieldValueImpl valueImpl = new CompositeFieldValueImpl(); valueImpl.setValuesAsCollection(composedFields); valueImpl.setType(FieldValueType.COMPOSITE.name()); fieldImpl.setValue(valueImpl); } break; } case COLLECTION: { CollectionDataType collectionFieldDef = (CollectionDataType) fieldDef.getValue().getValueDef(); CollectionFieldValueImpl fieldValueImpl = new CollectionFieldValueImpl(); fieldValueImpl.setType(FieldValueType.COLLECTION.name()); switch (collectionFieldDef.getItemDataType().getType()) { case COMPOSITE: { boolean hasCompositeValue = false; Map<String, Map<String, List<FormDataBodyPart>>> compositesCollection = new HashMap<String, Map<String, List<FormDataBodyPart>>>(); final String prefixPattern = new StringBuilder(fieldDef.getKey()).append("\\.([0-9]+)\\..+"). toString(); Pattern pattern = Pattern.compile(prefixPattern); for (String key : bodyParts.keySet()) { Matcher matcher = pattern.matcher(key); if (matcher.matches()) { hasCompositeValue = true; final Map<String, List<FormDataBodyPart>> composites; String groupKey = matcher.group(1); if (compositesCollection.containsKey(groupKey)) { composites = compositesCollection.get(groupKey); } else { composites = new LinkedHashMap<String, List<FormDataBodyPart>>(); compositesCollection.put(groupKey, composites); } composites.put(key.substring(matcher.end(1) + 1), bodyParts.get(key)); } } if (hasCompositeValue) { CompositeDataType compositeDataType = (CompositeDataType) collectionFieldDef.getItemDataType(); for (Entry<String, Map<String, List<FormDataBodyPart>>> cols : compositesCollection.entrySet()) { Collection<com.smartitengineering.cms.ws.common.domains.Field> composedFields = new ArrayList<com.smartitengineering.cms.ws.common.domains.Field>(); formFields(compositeDataType.getComposedFieldDefs(), cols.getValue(), composedFields); CompositeFieldValueImpl valueImpl = new CompositeFieldValueImpl(); valueImpl.setValuesAsCollection(composedFields); valueImpl.setType(FieldValueType.COMPOSITE.name()); fieldValueImpl.getValues().add(valueImpl); } } break; } default: if (containsKey) { for (FormDataBodyPart bodyPart : bodyParts.get(fieldDef.getKey())) { if (bodyPart == null || org.apache.commons.lang.StringUtils.isBlank(bodyPart.getValue())) { continue; } FieldValueImpl valueImpl = addFieldFromBodyPart(bodyPart, collectionFieldDef.getItemDataType()); if (valueImpl != null) { fieldValueImpl.getValues().add(valueImpl); } } } } if (fieldValueImpl.getValues().isEmpty()) { continue; } fieldImpl.setValue(fieldValueImpl); break; } case OTHER: { if (containsKey) { final FormDataBodyPart singleBodyPart = bodyParts.get(fieldDef.getKey()).get(0); FieldValueImpl valueImpl = addFieldFromBodyPart(singleBodyPart, fieldDef.getValue().getValueDef()); fieldImpl.setValue(valueImpl); } break; } default: { if (containsKey) { final FormDataBodyPart singleBodyPart = bodyParts.get(fieldDef.getKey()).get(0); if (singleBodyPart == null || org.apache.commons.lang.StringUtils.isBlank(singleBodyPart.getValue())) { continue; } FieldValueImpl valueImpl = addFieldFromBodyPart(singleBodyPart, fieldDef.getValue().getValueDef()); fieldImpl.setValue(valueImpl); } break; } } fields.add(fieldImpl); } } } protected static ContentTypeResource getContentTypeResource(String uri, ServerResourceInjectables injectables) throws ClassCastException, ContainerException { final URI checkUri; if (uri.startsWith("http:")) { checkUri = URI.create(uri); } else { URI absUri = injectables.getUriInfo().getBaseUriBuilder().build(); checkUri = UriBuilder.fromPath(uri).host(absUri.getHost()).port(absUri.getPort()).scheme(absUri.getScheme()).build(); } return injectables.getResourceContext().matchResource(checkUri, ContentTypeResource.class); } private static final byte[] TMP = new byte[0]; protected static FieldValueImpl addFieldFromBodyPart(FormDataBodyPart bodyPart, DataType dataType) { switch (dataType.getType()) { case STRING: OtherFieldValueImpl stringFieldValueImpl = new OtherFieldValueImpl(); stringFieldValueImpl.setType(dataType.getType().name()); stringFieldValueImpl.setMimeType(bodyPart.getMediaType().toString()); stringFieldValueImpl.setValue(bodyPart.getValue()); return stringFieldValueImpl; case OTHER: OtherFieldValueImpl otherFieldValueImpl = new OtherFieldValueImpl(); otherFieldValueImpl.setType(dataType.getType().name()); otherFieldValueImpl.setMimeType(bodyPart.getMediaType().toString()); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Body Part " + bodyPart.getMediaType()); } try { otherFieldValueImpl.setValue(Base64.encodeBase64String(bodyPart.getValueAs(TMP.getClass()))); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Field value " + otherFieldValueImpl.getValue()); } } catch (Exception ex) { LOGGER.warn("Entity not found!", ex); } return otherFieldValueImpl; case BOOLEAN: { FieldValueImpl valueImpl = new FieldValueImpl(); valueImpl.setType(dataType.getType().name()); if (org.apache.commons.lang.StringUtils.isNotBlank(bodyPart.getValue())) { valueImpl.setValue(bodyPart.getValue().equals("on") ? "true" : "false"); } else { valueImpl.setValue(bodyPart.getValue()); } return valueImpl; } default: { FieldValueImpl valueImpl = new FieldValueImpl(); valueImpl.setType(dataType.getType().name()); valueImpl.setValue(bodyPart.getValue()); return valueImpl; } } } @PUT @Consumes(MediaType.APPLICATION_JSON) public Response put(com.smartitengineering.cms.ws.common.domains.Content jsonContent, @HeaderParam(HttpHeaders.IF_MATCH) EntityTag etag) { LOGGER.info("Received JSON Object representation of Content!"); Content newContent; try { newContent = adapter.convertInversely(jsonContent); } catch (Exception ex) { LOGGER.warn("Could not convert to content!", ex); return Response.status(Response.Status.BAD_REQUEST).entity(ex.getMessage()).type(MediaType.TEXT_PLAIN).build(); } final WriteableContent writeableContent; if (this.content == null) { LOGGER.info("Processing as new content"); //Create new content writeableContent = SmartContentAPI.getInstance().getContentLoader().getWritableContent(newContent, importMode); } else { LOGGER.debug("Processing as content update"); //Update new content with etag checking if (etag == null) { return Response.status(Response.Status.PRECONDITION_FAILED).build(); } ResponseBuilder builder = getContext().getRequest().evaluatePreconditions(this.tag); if (builder != null) { return builder.build(); } //Merge new contents into the old one in case of update writeableContent = SmartContentAPI.getInstance().getContentLoader().getWritableContent(this.content, importMode); writeableContent.setContentDefinition(newContent.getContentDefinition()); writeableContent.setStatus(newContent.getStatus()); writeableContent.setParentId(newContent.getParentId()); for (Field field : newContent.getOwnFields().values()) { writeableContent.setField(field); } } //Set content id for new content with valid id if (this.content == null && contentId.getId() != null && contentId.getId().length > 0) { writeableContent.setContentId(contentId); } //Create new content id for new content with no specified id else if (this.content == null) { writeableContent.createContentId(contentId.getWorkspaceId()); } try { //Save or update the content, will be decided by writeable content implementation writeableContent.put(); } catch (IOException ex) { LOGGER.error("Could save/update content!", ex); return Response.serverError().build(); } final ResponseBuilder builder; if (this.content == null) { //Send 201 builder = Response.created(getContentUri(getAbsoluteURIBuilder(), writeableContent.getContentId())); } else { //Send 202 builder = Response.status(Response.Status.ACCEPTED); } return builder.build(); } @DELETE public Response delete(@HeaderParam(HttpHeaders.IF_MATCH) EntityTag etag) { LOGGER.info("Deleting a content"); if (content == null) { throw new WebApplicationException(Response.Status.NOT_FOUND); } if (etag == null) { return Response.status(Response.Status.PRECONDITION_FAILED).build(); } ResponseBuilder builder = getContext().getRequest().evaluatePreconditions(tag); if (builder == null) { WriteableContent writeableContent = SmartContentAPI.getInstance().getContentLoader().getWritableContent(content); try { writeableContent.delete(); builder = Response.ok(); } catch (Exception ex) { LOGGER.error("Could not delete due to server error!", ex); builder = Response.serverError(); } } return builder.build(); } public Content getContent() { return content; } public static URI getContentUri(UriBuilder builder, ContentId contentId) { builder.path(ContentsResource.class).path(ContentsResource.PATH_TO_CONTENT); return builder.build(contentId.getWorkspaceId().getGlobalNamespace(), contentId.getWorkspaceId().getName(), StringUtils.newStringUtf8(contentId.getId())); } @Override protected String getAuthor() { return "Smart CMS"; } public static class ContentAdapterHelper extends AbstractAdapterHelper<Content, com.smartitengineering.cms.ws.common.domains.Content> { private final ServerResourceInjectables injectables; private final boolean importMode; public ContentAdapterHelper(ServerResourceInjectables injectables, boolean importMode) { this.injectables = injectables; this.importMode = importMode; } @Override protected com.smartitengineering.cms.ws.common.domains.Content newTInstance() { return new ContentImpl(); } protected UriBuilder getRelativeURIBuilder() { return UriBuilder.fromPath(injectables.getUriInfo().getBaseUriBuilder().build().getPath()); } protected UriBuilder getAbsoluteURIBuilder() { return injectables.getUriInfo().getBaseUriBuilder(); } @Override protected void mergeFromF2T(Content fromBean, com.smartitengineering.cms.ws.common.domains.Content toBean) { ContentImpl contentImpl = (ContentImpl) toBean; contentImpl.setPrivateContent(fromBean.isPrivate()); ContentType type = fromBean.getContentDefinition(); if (fromBean.getContentId() != null) { contentImpl.setContentId(fromBean.getContentId().toString()); contentImpl.setSelfUri(ContentResource.getContentUri(getRelativeURIBuilder(), fromBean.getContentId()). toASCIIString()); contentImpl.setReindexUri(new StringBuilder(contentImpl.getSelfUri()).append('/').append(PATH_TO_REINDEX). toString()); } contentImpl.setContentTypeUri( ContentTypeResource.getContentTypeRelativeURI(injectables.getUriInfo(), type.getContentTypeID()).toASCIIString()); if (fromBean.getParentId() != null) { contentImpl.setParentContentUri(ContentResource.getContentUri(getRelativeURIBuilder(), fromBean.getParentId()). toASCIIString()); } contentImpl.setCreationDate(fromBean.getCreationDate()); contentImpl.setLastModifiedDate(fromBean.getLastModifiedDate()); final ContentStatus status = fromBean.getStatus(); if (status != null) { contentImpl.setStatus(status.getName()); } Map<String, Field> fields = fromBean.getFields(); if (LOGGER.isDebugEnabled()) { LOGGER.debug("FIELDS: " + fields); } String contentUri = ContentResource.getContentUri(getRelativeURIBuilder(), fromBean.getContentId()).toASCIIString(); for (FieldDef fieldDef : type.getFieldDefs().values()) { FieldImpl fieldImpl = convertToDomainField(getRelativeURIBuilder(), fieldDef, fields, contentUri); if (fieldImpl != null) { contentImpl.getFields().add(fieldImpl); } } Collection<RepresentationDef> defs = type.getRepresentationDefs().values(); String currentContext = new StringBuilder(contentUri).append("/r/").toString(); Map<String, String> repUris = contentImpl.getRepresentations(); Map<String, String> repNames = contentImpl.getRepresentationsByName(); for (RepresentationDef def : defs) { final String uri = new StringBuilder(currentContext).append(def.getName()).toString(); repUris.put(uri, def.getMIMEType()); repNames.put(def.getName(), uri); } } @Override protected Content convertFromT2F(com.smartitengineering.cms.ws.common.domains.Content toBean) { final ContentType contentType; try { ContentTypeResource resource = getContentTypeResource(toBean.getContentTypeUri(), injectables); if (resource == null) { throw new NullPointerException("No such content type!"); } contentType = resource.getType(); } catch (Exception ex) { throw new RuntimeException(ex.getMessage(), ex); } WriteableContent writeableContent = SmartContentAPI.getInstance().getContentLoader().createContent(contentType); ContentStatus status = contentType.getStatuses().get(toBean.getStatus()); if (status == null) { throw new IllegalArgumentException("No such status in content type!"); } writeableContent.setStatus(status); writeableContent.setPrivate(toBean.isPrivateContent()); ContentId parentContentId; final String parentContentUri = toBean.getParentContentUri(); if (org.apache.commons.lang.StringUtils.isNotBlank(parentContentUri)) { try { final ContentResource resource = getContentResource(parentContentUri, getAbsoluteURIBuilder(), injectables.getResourceContext()); if (resource == null) { throw new NullPointerException("No such parent content!"); } if (!importMode && resource.getContent() == null) { throw new NullPointerException("No such parent content!"); } parentContentId = resource.getContentId(); } catch (Exception ex) { throw new RuntimeException(ex.getMessage(), ex); } writeableContent.setParentId(parentContentId); } for (com.smartitengineering.cms.ws.common.domains.Field field : toBean.getFields()) { MutableField mutableField = getField(writeableContent.getContentId(), contentType.getFieldDefs().get( field.getName()), field, injectables.getResourceContext(), getAbsoluteURIBuilder(), importMode); writeableContent.setField(mutableField); } return writeableContent; } } protected static FieldValue getFieldValue(final DataType dataType, com.smartitengineering.cms.ws.common.domains.FieldValue value, ResourceContext context, UriBuilder absBuilder, boolean importMode) { FieldValue fieldValue; if (LOGGER.isDebugEnabled()) { LOGGER.debug("Parsing value as " + dataType.getType().name()); } switch (dataType.getType()) { case COMPOSITE: { LOGGER.debug("Parsing as composite"); MutableCompositeFieldValue compositeFieldValue = SmartContentAPI.getInstance().getContentLoader(). createCompositeFieldValue(); CompositeFieldValue compositeValue = (CompositeFieldValue) value; CompositeDataType compositeDataType = (CompositeDataType) dataType; Collection<Field> composedOf = new ArrayList<Field>(compositeValue.getValues().size()); Map<String, FieldDef> fieldDefs = compositeDataType.getComposedFieldDefs(); for (Entry<String, com.smartitengineering.cms.ws.common.domains.Field> field : compositeValue.getValues(). entrySet()) { FieldDef def = fieldDefs.get(field.getKey()); if (def == null) { throw new NullPointerException("No such field definition within composed field"); } MutableField mutableField = getField(null, def, field.getValue(), context, absBuilder, importMode); composedOf.add(mutableField); } compositeFieldValue.setValue(composedOf); fieldValue = compositeFieldValue; break; } case COLLECTION: LOGGER.debug("Parsing as collection"); MutableCollectionFieldValue collectionFieldValue = SmartContentAPI.getInstance().getContentLoader(). createCollectionFieldValue(); CollectionDataType collectionDataType = (CollectionDataType) dataType; com.smartitengineering.cms.ws.common.domains.CollectionFieldValue cFieldValue = (com.smartitengineering.cms.ws.common.domains.CollectionFieldValue) value; ArrayList<FieldValue> list = new ArrayList<FieldValue>(cFieldValue.getValues().size()); for (com.smartitengineering.cms.ws.common.domains.FieldValue v : cFieldValue.getValues()) { list.add(getFieldValue(collectionDataType.getItemDataType(), v, context, absBuilder, importMode)); } collectionFieldValue.setValue(list); fieldValue = collectionFieldValue; break; case CONTENT: LOGGER.debug("Parsing string as Content!"); MutableContentFieldValue contentFieldValue = SmartContentAPI.getInstance().getContentLoader(). createContentFieldValue(); String contentUrl = value.getValue(); if (LOGGER.isDebugEnabled()) { LOGGER.debug("URL to content is " + contentUrl); } try { ContentResource resource = getContentResource(contentUrl, absBuilder, context); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Resource " + resource); } if (resource == null) { throw new NullPointerException(); } if (LOGGER.isDebugEnabled()) { LOGGER.debug("Content ID " + resource.getContentId()); } if (!importMode && resource.getContent() == null) { throw new NullPointerException("No such content! " + resource.getContentId()); } contentFieldValue.setValue(resource.getContentId()); } catch (Exception ex) { LOGGER.warn("Error getting content!", ex); throw new IllegalArgumentException("Invalid Content URI!"); } fieldValue = contentFieldValue; break; default: LOGGER.debug("Parsing as default or all other than content and collection"); fieldValue = SmartContentAPI.getInstance().getContentLoader().getValueFor(value.getValue(), dataType); } return fieldValue; } protected static MutableField getField(final ContentId contentId, final FieldDef fieldDef, com.smartitengineering.cms.ws.common.domains.Field field, ResourceContext context, UriBuilder absBuilder, boolean importMode) throws IllegalArgumentException { if (fieldDef == null) { throw new IllegalArgumentException("No field in content type with name " + field.getName()); } final DataType dataType = fieldDef.getValueDef(); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Working with field " + field.getName() + " of type " + dataType.getType().name() + " with value " + field.getValue()); } if (field.getValue() != null && org.apache.commons.lang.StringUtils.isNotBlank(field.getValue().getType()) && !org.apache.commons.lang.StringUtils.equalsIgnoreCase(dataType.getType().name(), field.getValue().getType())) { throw new IllegalArgumentException("Type mismatch! NOTE: type of values in field is optional in this case. " + "Field is " + field.getName() + " - " + dataType.getType().name() + " " + field.getValue().getType()); } final MutableField mutableField = SmartContentAPI.getInstance().getContentLoader().createMutableField(contentId, fieldDef); final FieldValue fieldValue; if (field.getValue() != null) { fieldValue = getFieldValue(dataType, field.getValue(), context, absBuilder, importMode); } else { fieldValue = null; } mutableField.setValue(fieldValue); return mutableField; } protected static ContentResource getContentResource(String contentUrl, UriBuilder absBuilder, ResourceContext context) throws ContainerException, IllegalArgumentException, ClassCastException, UriBuilderException { final URI uri; if (contentUrl.startsWith("http:")) { uri = URI.create(contentUrl); } else { URI absUri = absBuilder.build(); uri = UriBuilder.fromPath(contentUrl).host(absUri.getHost()).port(absUri.getPort()).scheme(absUri.getScheme()).build(); } if (LOGGER.isDebugEnabled()) { LOGGER.debug("URI to content is " + uri); } ContentResource resource = context.matchResource(uri, ContentResource.class); return resource; } protected static void getDomainField(UriBuilder builder, Field field, String contentUri, FieldImpl fieldImpl) { if (field != null && org.apache.commons.lang.StringUtils.isNotBlank(field.getName()) && field.getValue() != null) { fieldImpl.setName(field.getName()); final FieldValueImpl value; final FieldValue contentFieldValue = field.getValue(); final DataType valueDef = field.getFieldDef().getValueDef(); value = getFieldvalue(builder, valueDef, contentFieldValue); if (org.apache.commons.lang.StringUtils.isNotBlank(contentUri)) { Collection<VariationDef> defs = field.getFieldDef().getVariations().values(); Map<String, String> variations = fieldImpl.getVariations(); Map<String, String> variationsByNames = fieldImpl.getVariationsByNames(); final String fieldUri = new StringBuilder(contentUri).append("/f/").append(field.getName()).toString(); fieldImpl.setFieldUri(fieldUri); fieldImpl.setFieldRawContentUri(new StringBuilder(fieldUri).append("/raw").toString()); for (VariationDef def : defs) { final String uri = new StringBuilder(fieldUri).append("/v/").append(def.getName()).toString(); variations.put(uri, def.getMIMEType()); variationsByNames.put(def.getName(), uri); } } fieldImpl.setValue(value); } else { if (LOGGER.isWarnEnabled()) { String fieldError = ((field == null) ? "NULL Field" : ((org.apache.commons.lang.StringUtils.isBlank(field. getName()) ? "NULL Name" : ((field.getValue() == null) ? "NULL Value" : "Indeterministic error!")))); if (!fieldError.contains("Name")) { fieldError = new StringBuilder(fieldError).append(' ').append(field.getName()).toString(); } LOGGER.warn("Invalid field! " + fieldError); } } } private static FieldValueImpl getFieldvalue(final UriBuilder builder, final DataType valueDef, final FieldValue contentFieldValue) { final FieldValueImpl value; switch (valueDef.getType()) { case CONTENT: { FieldValueImpl valueImpl = new FieldValueImpl(); valueImpl.setValue(ContentResource.getContentUri(builder.clone(), ((ContentFieldValue) contentFieldValue). getValue()). toASCIIString()); value = valueImpl; break; } case COLLECTION: { CollectionFieldValueImpl valueImpl = new CollectionFieldValueImpl(); Collection<FieldValue> contentValues = ((CollectionFieldValue) contentFieldValue).getValue(); final DataType itemDataType = ((CollectionDataType) valueDef).getItemDataType(); for (FieldValue contentValue : contentValues) { valueImpl.getValues().add(getFieldvalue(builder.clone(), itemDataType, contentValue)); } value = valueImpl; break; } case COMPOSITE: { CompositeFieldValueImpl valueImpl = new CompositeFieldValueImpl(); Map<String, Field> composedFields = ((com.smartitengineering.cms.api.content.CompositeFieldValue) contentFieldValue). getValueAsMap(); final Map<String, FieldDef> composedFieldDefs = ((CompositeDataType) valueDef).getComposedFieldDefs(); for (Entry<String, Field> composeeField : composedFields.entrySet()) { valueImpl.getValues().put(composeeField.getKey(), convertToDomainField(builder.clone(), composedFieldDefs.get(composeeField.getKey()), composedFields, "")); } value = valueImpl; break; } case OTHER: case STRING: { OtherFieldValueImpl valueImpl = new OtherFieldValueImpl(); valueImpl.setValue(contentFieldValue.toString()); valueImpl.setMimeType(((OtherDataType) valueDef).getMIMEType()); value = valueImpl; break; } default: { FieldValueImpl valueImpl = new FieldValueImpl(); valueImpl.setValue(contentFieldValue.toString()); value = valueImpl; } } value.setType(valueDef.getType().toString()); return value; } protected static FieldImpl convertToDomainField(UriBuilder builder, FieldDef fieldDef, Map<String, Field> fields, String contentUri) { final String fieldName = fieldDef.getName(); Field field = fields.get(fieldName); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Field " + field); if (field != null) { LOGGER.debug("Converting field " + field.getName() + " with value " + field.getValue() + " and URI " + contentUri); } } FieldImpl fieldImpl; if (field != null) { fieldImpl = new FieldImpl(); fieldImpl.setName(fieldName); getDomainField(builder, field, contentUri, fieldImpl); } else { fieldImpl = null; } return fieldImpl; } protected ContentId getContentId() { return contentId; } }