/*
*
* 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;
}
}