com.smartitengineering.cms.ws.resources.content.FieldResource.java Source code

Java tutorial

Introduction

Here is the source code for com.smartitengineering.cms.ws.resources.content.FieldResource.java

Source

/*
 *
 * 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.BooleanFieldValue;
import com.smartitengineering.cms.api.content.CollectionFieldValue;
import com.smartitengineering.cms.api.content.CompositeFieldValue;
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.DateTimeFieldValue;
import com.smartitengineering.cms.api.content.Field;
import com.smartitengineering.cms.api.content.FieldValue;
import com.smartitengineering.cms.api.content.NumberFieldValue;
import com.smartitengineering.cms.api.factory.SmartContentAPI;
import com.smartitengineering.cms.api.factory.content.WriteableContent;
import com.smartitengineering.cms.api.type.CompositeDataType;
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.StringDataType;
import com.smartitengineering.cms.ws.common.domains.FieldImpl;
import com.smartitengineering.cms.ws.common.providers.TextURIListProvider;
import com.smartitengineering.cms.ws.common.utils.Utils;
import com.smartitengineering.cms.ws.resources.ResourcesConfig;
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 java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
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.Response.Status;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.Variant;
import org.apache.abdera.model.Entry;
import org.apache.abdera.model.Feed;
import org.apache.abdera.model.Link;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author imyousuf
 */
public class FieldResource extends AbstractResource {

    private final Content content;
    private final FieldDef fieldDef;
    private final EntityTag entityTag;
    private final Field preinitField;
    protected final GenericAdapter<Field, com.smartitengineering.cms.ws.common.domains.Field> adapter;
    protected final transient Logger logger = LoggerFactory.getLogger(getClass());
    public static final String PATH_TO_VAR = "v/{varName}";

    public FieldResource(ServerResourceInjectables injectables, Content content, FieldDef fieldDef,
            EntityTag eTag) {
        this(injectables, content, fieldDef, eTag, null);
    }

    public FieldResource(ServerResourceInjectables injectables, Content content, FieldDef fieldDef, EntityTag eTag,
            Field field) {
        super(injectables);
        if (content == null || fieldDef == null) {
            logger.warn("No content or field def", new NullPointerException());
            throw new WebApplicationException(Status.NOT_FOUND);
        }
        this.content = content;
        this.fieldDef = fieldDef;
        GenericAdapterImpl adapterImpl = new GenericAdapterImpl<Field, com.smartitengineering.cms.ws.common.domains.Field>();
        adapterImpl.setHelper(new FieldAdapterHelper());
        this.adapter = adapterImpl;
        this.entityTag = eTag;
        this.preinitField = field;
    }

    @Path(PATH_TO_VAR)
    public VariationResource getVariation(@PathParam("varName") String varName) {
        Field field = getCurrentField();
        if (field != null) {
            return new VariationResource(getInjectables(), content, field, varName);
        } else {
            throw new WebApplicationException(Status.NOT_FOUND);
        }
    }

    @GET
    @Path("/f/{fieldName}")
    public FieldResource getComposedField(@PathParam("fieldName") final String nestedFieldName) {
        if (!fieldDef.getValueDef().getType().equals(FieldValueType.COMPOSITE)) {
            throw new WebApplicationException(Status.BAD_REQUEST);
        }
        CompositeDataType compositeFieldDef = (CompositeDataType) fieldDef.getValueDef();
        FieldDef newFieldDef = compositeFieldDef.getComposedFieldDefs().get(nestedFieldName);
        CompositeFieldValue compositeFieldValue = (CompositeFieldValue) getCurrentField().getValue();
        return new FieldResource(getInjectables(), content, newFieldDef, entityTag,
                compositeFieldValue.getValueAsMap().get(nestedFieldName));
    }

    @GET
    @Path("/raw/abs")
    public Response getAbsoluteRaw() {
        ResponseBuilder builder = getContext().getRequest().evaluatePreconditions(content.getLastModifiedDate(),
                entityTag);
        if (builder == null) {
            Field field = getCurrentField();
            if (field == null) {
                builder = Response.status(Status.NOT_FOUND);
            } else {
                builder = Response.ok().tag(entityTag);
                processDefaultRawContent(builder);
            }
            CacheControl control = new CacheControl();
            control.setMaxAge(ResourcesConfig.getInstance().getFieldHttpCacheControlMaxAge());
            builder.cacheControl(control);
        }
        return builder.build();
    }

    protected Field getCurrentField() {
        if (preinitField != null) {
            return preinitField;
        } else {
            return content.getField(fieldDef.getName());
        }
    }

    @GET
    @Path("/raw")
    public Response getRaw() {
        boolean useDefault = false;
        List<MediaType> accepts = getContext().getRequest().getAcceptableMediaTypes();
        if (accepts == null || accepts.isEmpty()) {
            useDefault = true;
        }
        ResponseBuilder builder = getContext().getRequest().evaluatePreconditions(content.getLastModifiedDate(),
                entityTag);
        if (builder == null) {
            Field field = getCurrentField();
            if (field == null) {
                builder = Response.status(Status.NOT_FOUND);
            } else {
                builder = Response.ok().tag(entityTag);
                if (useDefault) {
                    processDefaultRawContent(builder);
                } else {
                    final MediaType fieldValueDefaultMimeType = getFieldValueDefaultMimeType(
                            fieldDef.getValueDef());
                    MediaType type = getUserPreferredType(fieldValueDefaultMimeType);
                    if (type == null) {
                        final List<Variant> variants = getVariants(MediaType.APPLICATION_ATOM_XML_TYPE,
                                fieldValueDefaultMimeType, MediaType.APPLICATION_JSON_TYPE,
                                MediaType.APPLICATION_XML_TYPE, MediaType.APPLICATION_XML_TYPE,
                                MediaType.TEXT_XML_TYPE);
                        return Response.notAcceptable(variants).build();
                    } else if (type.equals(MediaType.APPLICATION_ATOM_XML_TYPE)
                            || type.equals(MediaType.TEXT_XML_TYPE)
                            || type.equals(MediaType.APPLICATION_XML_TYPE)) {
                        processAtomFeedAsRawContent(builder);
                    } else if (type.toString().equals(MediaType.MEDIA_TYPE_WILDCARD)
                            || type.equals(fieldValueDefaultMimeType)) {
                        processDefaultRawContent(builder);
                    } else {
                        return Response.seeOther(getFieldUri()).build();
                    }
                }
                CacheControl control = new CacheControl();
                control.setMaxAge(ResourcesConfig.getInstance().getFieldHttpCacheControlMaxAge());
                builder.header(HttpHeaders.VARY, HttpHeaders.ACCEPT);
                builder.cacheControl(control);
            }
        }
        return builder.build();
    }

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response get() {
        ResponseBuilder builder = getContext().getRequest().evaluatePreconditions(content.getLastModifiedDate(),
                entityTag);
        if (builder == null) {
            Field field = getCurrentField();
            if (field == null) {
                builder = Response.status(Status.NOT_FOUND);
            } else {
                builder = Response.ok(adapter.convert(field)).lastModified(content.getLastModifiedDate())
                        .tag(entityTag);
                CacheControl control = new CacheControl();
                control.setMaxAge(ResourcesConfig.getInstance().getFieldHttpCacheControlMaxAge());
                builder.cacheControl(control);
            }
        }
        return builder.build();
    }

    @DELETE
    public Response delete(@HeaderParam(HttpHeaders.IF_MATCH) EntityTag ifMatchHeader) {
        if (!fieldDef.isFieldStandaloneUpdateAble()) {
            return Response.status(Status.FORBIDDEN).build();
        }
        final boolean isAvailable = getCurrentField() != null;
        if (!isAvailable) {
            return Response.status(Status.NOT_FOUND).build();
        }
        if (ifMatchHeader == null) {
            return Response.status(Status.PRECONDITION_FAILED).build();
        }
        ResponseBuilder builder = getContext().getRequest().evaluatePreconditions(content.getLastModifiedDate(),
                entityTag);
        if (builder == null) {
            WriteableContent writeableContent = SmartContentAPI.getInstance().getContentLoader()
                    .getWritableContent(content);
            writeableContent.removeField(fieldDef.getName());
            boolean error = false;
            try {
                writeableContent.put();
            } catch (Exception ex) {
                logger.error("Could not update field by updating content!", ex);
                builder = Response.status(Status.INTERNAL_SERVER_ERROR).entity(ex.getMessage());
                error = true;
            }
            if (!error) {
                builder = Response.ok();
            }
        }
        return builder.build();
    }

    @PUT
    @Consumes(MediaType.APPLICATION_JSON)
    public Response put(com.smartitengineering.cms.ws.common.domains.Field field,
            @HeaderParam(HttpHeaders.IF_MATCH) EntityTag ifMatchHeader) {

        if (!fieldDef.isFieldStandaloneUpdateAble()) {
            return Response.status(Status.FORBIDDEN).build();
        }
        final boolean isUpdate = content.getField(field.getName()) != null;
        if (isUpdate && ifMatchHeader == null) {
            return Response.status(Status.PRECONDITION_FAILED).build();
        }
        ResponseBuilder builder = getContext().getRequest().evaluatePreconditions(content.getLastModifiedDate(),
                entityTag);
        if (builder == null) {
            boolean error = false;
            WriteableContent writeableContent = SmartContentAPI.getInstance().getContentLoader()
                    .getWritableContent(content);
            try {
                writeableContent.setField(adapter.convertInversely(field));
            } catch (Exception ex) {
                logger.warn("Could not convert to field!", ex);
                builder = Response.status(Status.BAD_REQUEST).entity(ex.getMessage());
                error = true;
            }
            try {
                writeableContent.put();
            } catch (Exception ex) {
                logger.error("Could not update field by updating content!", ex);
                builder = Response.status(Status.INTERNAL_SERVER_ERROR).entity(ex.getMessage());
                error = true;
            }
            if (!error) {
                if (isUpdate) {
                    builder = Response.status(Status.ACCEPTED);
                } else {
                    builder = Response.created(UriBuilder
                            .fromUri(ContentResource.getContentUri(getAbsoluteURIBuilder(), content.getContentId()))
                            .path(field.getName()).build());
                }
            }
        }
        return builder.build();
    }

    protected Collection<Entry> getEntries(final FieldValue value, final Date lastModifiedDate, String... id)
            throws IllegalArgumentException {
        final List<Entry> entries = new ArrayList<Entry>();
        final String mimeType = getFieldValueDefaultMimeType(fieldDef.getValueDef()).toString();
        switch (fieldDef.getValueDef().getType()) {
        case BOOLEAN:
            BooleanFieldValue booleanFieldValue = (BooleanFieldValue) value;
            Entry entry = getEntry("value", "Value", lastModifiedDate);
            entry.setContent(Boolean.toString(booleanFieldValue.getValue()), mimeType);
            entries.add(entry);
            break;
        case COLLECTION:
            CollectionFieldValue collectionFieldValue = (CollectionFieldValue) value;
            int index = 0;
            for (FieldValue fieldValue : collectionFieldValue.getValue()) {
                entries.addAll(getEntries(fieldValue, lastModifiedDate,
                        new StringBuilder("value-").append(index++).toString()));
            }
            break;
        case CONTENT:
            ContentFieldValue contentFieldValue = (ContentFieldValue) value;
            entry = getEntry(StringUtils.defaultIfEmpty(id[0], "value"), "Value", lastModifiedDate,
                    getLink(ContentResource.getContentUri(getRelativeURIBuilder(), contentFieldValue.getValue()),
                            Link.REL_ALTERNATE, mimeType));
            entries.add(entry);
            break;
        case DATE_TIME:
            DateTimeFieldValue dateTimeFieldValue = (DateTimeFieldValue) value;
            entry = getEntry("value", "Value", lastModifiedDate);
            entry.setContent(Utils.getFormattedDate(dateTimeFieldValue.getValue()), mimeType);
            entries.add(entry);
            break;
        case DOUBLE:
        case INTEGER:
        case LONG:
            NumberFieldValue numberFieldValue = (NumberFieldValue) value;
            entry = getEntry("value", "Value", lastModifiedDate);
            entry.setContent(numberFieldValue.getValue().toString(), mimeType);
            entries.add(entry);
            break;
        case STRING:
        case OTHER:
            OtherDataType otherDataType = (OtherDataType) fieldDef.getValueDef();
            entry = getEntry("value", "Value", lastModifiedDate);
            entry.setContent(String.valueOf(value), mimeType);
            entries.add(entry);
            break;
        }
        return entries;
    }

    public static MediaType getFieldValueDefaultMimeType(DataType value) {
        switch (value.getType()) {
        case COLLECTION:
            return MediaType.APPLICATION_ATOM_XML_TYPE;
        case CONTENT:
            return TextURIListProvider.TEXT_URI_LIST_TYPE;
        case DATE_TIME:
        case DOUBLE:
        case INTEGER:
        case LONG:
        case BOOLEAN:
        default:
            return MediaType.TEXT_PLAIN_TYPE;
        case STRING:
        case OTHER:
            OtherDataType otherDataType = (OtherDataType) value;
            return MediaType.valueOf(otherDataType.getMIMEType());
        }
    }

    private void processDefaultRawContent(ResponseBuilder builder) {
        final Field field = getCurrentField();
        final FieldValue value = field.getValue();
        final MediaType mimeType = getFieldValueDefaultMimeType(fieldDef.getValueDef());
        switch (fieldDef.getValueDef().getType()) {
        case BOOLEAN:
            BooleanFieldValue booleanFieldValue = (BooleanFieldValue) value;
            builder.entity(booleanFieldValue.getValue()).type(mimeType);
            break;
        case COLLECTION:
            processAtomFeedAsRawContent(builder);
            break;
        case CONTENT:
            ContentFieldValue contentFieldValue = (ContentFieldValue) value;
            builder.entity(Collections.singleton(
                    ContentResource.getContentUri(getRelativeURIBuilder(), contentFieldValue.getValue())))
                    .type(mimeType);
            break;
        case DATE_TIME:
            DateTimeFieldValue dateTimeFieldValue = (DateTimeFieldValue) value;
            builder.entity(Utils.getFormattedDate(dateTimeFieldValue.getValue())).type(mimeType);
            break;
        case DOUBLE:
        case INTEGER:
        case LONG:
            NumberFieldValue numberFieldValue = (NumberFieldValue) value;
            builder.entity(numberFieldValue.getValue().toString()).type(mimeType);
            break;
        case STRING:
            StringDataType stringDataType = (StringDataType) fieldDef.getValueDef();
            final String encoding = stringDataType.getEncoding();
            if (StringUtils.isNotBlank(encoding)) {
                builder.header(HttpHeaders.CONTENT_ENCODING, encoding);
            }
        case OTHER:
            builder.entity(value.getValue());
            builder.type(mimeType);
            break;
        }
    }

    private void processAtomFeedAsRawContent(ResponseBuilder builder) {
        final String toString = new StringBuilder(content.getContentId().toString()).append(':')
                .append(fieldDef.getName()).toString();
        final Date lastModifiedDate = content.getLastModifiedDate();
        Feed feed = getFeed(toString, toString, lastModifiedDate);
        feed.addLink(getLink(getFieldUri(), Link.REL_EDIT, MediaType.APPLICATION_JSON));
        final Field field = getCurrentField();
        final FieldValue value = field.getValue();
        Collection<Entry> entries = getEntries(value, lastModifiedDate);
        for (Entry entry : entries) {
            feed.addEntry(entry);
        }
        if (!value.getDataType().equals(FieldValueType.COLLECTION)) {
            feed.addLink(getLink(UriBuilder.fromUri(getFieldUri()).path("raw").build(), Link.REL_ALTERNATE,
                    getFieldValueDefaultMimeType(fieldDef.getValueDef()).toString()));
        }
        builder.entity(feed).type(MediaType.APPLICATION_ATOM_XML);
    }

    private URI getFieldUri() {
        return getFieldURI(getAbsoluteURIBuilder(), content, fieldDef);
    }

    public static URI getFieldURI(UriBuilder builder, Content content, FieldDef fieldDef) {
        return getFieldURI(builder, content.getContentId(), fieldDef);
    }

    public static URI getFieldRawURI(UriBuilder builder, Content content, FieldDef fieldDef) {
        return getFieldRawURI(builder, content.getContentId(), fieldDef);
    }

    public static URI getFieldAbsRawURI(UriBuilder builder, Content content, FieldDef fieldDef) {
        return getFieldAbsRawURI(builder, content.getContentId(), fieldDef);
    }

    public static URI getFieldURI(UriBuilder builder, ContentId contentId, FieldDef fieldDef) {
        return UriBuilder.fromUri(ContentResource.getContentUri(builder, contentId)).path("f")
                .path(fieldDef.getName()).build();
    }

    public static URI getFieldRawURI(UriBuilder builder, ContentId contentId, FieldDef fieldDef) {
        return UriBuilder.fromUri(ContentResource.getContentUri(builder, contentId)).path("f")
                .path(fieldDef.getName()).path("raw").build();
    }

    public static URI getFieldAbsRawURI(UriBuilder builder, ContentId contentId, FieldDef fieldDef) {
        return UriBuilder.fromUri(ContentResource.getContentUri(builder, contentId)).path("f")
                .path(fieldDef.getName()).path("raw").path("abs").build();
    }

    @Override
    protected String getAuthor() {
        return "Smart CMS";
    }

    private MediaType getUserPreferredType(MediaType defaultType) {
        return getContext().getRequest()
                .selectVariant(getVariants(defaultType, MediaType.APPLICATION_ATOM_XML_TYPE,
                        MediaType.APPLICATION_JSON_TYPE, MediaType.APPLICATION_XML_TYPE, MediaType.TEXT_XML_TYPE,
                        MediaType.WILDCARD_TYPE))
                .getMediaType();
    }

    private List<Variant> getVariants(MediaType... mediaTypes) {
        return Variant.mediaTypes(mediaTypes).add().build();
    }

    class FieldAdapterHelper
            extends AbstractAdapterHelper<Field, com.smartitengineering.cms.ws.common.domains.Field> {

        @Override
        protected com.smartitengineering.cms.ws.common.domains.Field newTInstance() {
            return new FieldImpl();
        }

        @Override
        protected void mergeFromF2T(Field fromBean, com.smartitengineering.cms.ws.common.domains.Field toBean) {
            ContentResource.getDomainField(getRelativeURIBuilder(), fromBean,
                    ContentResource.getContentUri(getRelativeURIBuilder(), content.getContentId()).toASCIIString(),
                    (FieldImpl) toBean);
        }

        @Override
        protected Field convertFromT2F(com.smartitengineering.cms.ws.common.domains.Field toBean) {
            return ContentResource.getField(content.getContentId(), fieldDef, toBean, getResourceContext(),
                    getAbsoluteURIBuilder(), false);
        }
    }
}