Package org.structr.rest.resource

Source Code of org.structr.rest.resource.TypeResource

/**
* Copyright (C) 2010-2014 Morgner UG (haftungsbeschränkt)
*
* This file is part of Structr <http://structr.org>.
*
* Structr 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.
*
* Structr 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 Structr.  If not, see <http://www.gnu.org/licenses/>.
*/
package org.structr.rest.resource;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.structr.common.GraphObjectComparator;
import org.structr.common.SecurityContext;
import org.structr.common.error.EmptyPropertyToken;
import org.structr.common.error.ErrorBuffer;
import org.structr.common.error.FrameworkException;
import org.structr.core.GraphObject;
import org.structr.core.Result;
import org.structr.core.app.App;
import org.structr.core.app.Query;
import org.structr.core.app.StructrApp;
import org.structr.core.entity.AbstractNode;
import org.structr.core.entity.AbstractRelationship;
import org.structr.core.entity.Relation;
import org.structr.core.graph.NodeInterface;
import org.structr.core.graph.RelationshipInterface;
import org.structr.core.graph.search.SearchCommand;
import org.structr.core.graph.search.SearchNodeCommand;
import org.structr.core.graph.search.SearchRelationshipCommand;
import org.structr.core.notion.Notion;
import org.structr.core.property.Property;
import org.structr.core.property.PropertyKey;
import org.structr.core.property.PropertyMap;
import org.structr.rest.RestMethodResult;
import org.structr.rest.exception.IllegalPathException;
import org.structr.rest.exception.NotFoundException;
import org.structr.rest.servlet.JsonRestServlet;
import org.structr.schema.SchemaHelper;

//~--- classes ----------------------------------------------------------------

/**
* Represents a bulk type match. A TypeResource will always result in a
* list of elements when it is the last element in an URI. A TypeResource
* that is not the first element in an URI will try to find a pre-defined
* relationship between preceding and the node type and follow that path.
*
* @author Christian Morgner
*/
public class TypeResource extends SortableResource {

  private static final Logger logger = Logger.getLogger(TypeResource.class.getName());

  //~--- fields ---------------------------------------------------------

  protected Class<? extends SearchCommand> searchCommandType = null;
  protected Class entityClass                                = null;
  protected String rawType                                   = null;
  protected HttpServletRequest request                       = null;
  protected Query query                                      = null;
  protected boolean isNode                                   = true;

  //~--- methods --------------------------------------------------------

  @Override
  public boolean checkAndConfigure(String part, SecurityContext securityContext, HttpServletRequest request) throws FrameworkException {

//    this.searchContext   = new SearchContext();
    this.securityContext = securityContext;
    this.request         = request;
    this.rawType         = part;

    if (rawType != null) {

      final boolean inexactSearch = parseInteger(request.getParameter(JsonRestServlet.REQUEST_PARAMETER_LOOSE_SEARCH)) == 1;
      final App app               = StructrApp.getInstance(securityContext);

      // test if resource class exists
      entityClass = SchemaHelper.getEntityClassForRawType(rawType);
      if (entityClass != null) {

        if (AbstractRelationship.class.isAssignableFrom(entityClass)) {

          searchCommandType = SearchRelationshipCommand.class;
          query             = app.relationshipQuery(entityClass, !inexactSearch);
          isNode            = false;
          return true;

        } else {

          // include interfaces here
          searchCommandType = SearchNodeCommand.class;
          query             = app.nodeQuery(entityClass, !inexactSearch);
          isNode            = true;
          return true;
        }
      }
    }

    return true;

  }

  @Override
  public Result doGet(final PropertyKey sortKey, final boolean sortDescending, final int pageSize, final int page, final String offsetId) throws FrameworkException {

    boolean includeDeletedAndHidden        = false;
    boolean publicOnly                     = false;
    PropertyKey actualSortKey              = sortKey;
    boolean actualSortOrder                = sortDescending;

    if (rawType != null) {

      if (entityClass == null) {
        throw new NotFoundException();
      }

      collectSearchAttributes(query);

      // default sort key & order
      if (actualSortKey == null) {

        try {

          GraphObject templateEntity  = ((GraphObject)entityClass.newInstance());
          PropertyKey sortKeyProperty = templateEntity.getDefaultSortKey();
          actualSortOrder             = GraphObjectComparator.DESCENDING.equals(templateEntity.getDefaultSortOrder());

          if (sortKeyProperty != null) {

            actualSortKey = sortKeyProperty;

          } else {

            actualSortKey = AbstractNode.name;
          }

        } catch(Throwable t) {

          // fallback to name
          actualSortKey = AbstractNode.name;
        }
      }

      // do search: FIXME: this doesn't work for inexact search because
      // the type search attribute has to be lowercase in the fulltext indices..
      return query
        .includeDeletedAndHidden(includeDeletedAndHidden)
        .publicOnly(publicOnly)
        .sort(actualSortKey)
        .order(actualSortOrder)
        .pageSize(pageSize)
        .page(page)
        .offsetId(offsetId)
        .getResult();

    } else {

      logger.log(Level.WARNING, "type was null");
    }

    List emptyList = Collections.emptyList();
    return new Result(emptyList, null, isCollectionResource(), isPrimitiveArray());
  }

  @Override
  public RestMethodResult doPost(final Map<String, Object> propertySet) throws FrameworkException {

    if (isNode) {

      final App app         = StructrApp.getInstance(securityContext);
      NodeInterface newNode = null;

      newNode = createNode(propertySet);

      final RestMethodResult result = new RestMethodResult(HttpServletResponse.SC_CREATED);
      if (newNode != null) {

        result.addHeader("Location", buildLocationHeader(newNode));
        result.addContent(newNode);
      }

      result.serializeAsPrimitiveArray(true);
     
      // finally: return 201 Created
      return result;

    } else {

      final App app                         = StructrApp.getInstance(securityContext);
      final Relation template               = getRelationshipTemplate();
      final ErrorBuffer errorBuffer         = new ErrorBuffer();

      if (template != null) {

        final NodeInterface sourceNode        = identifyStartNode(template, propertySet);
        final NodeInterface targetNode        = identifyEndNode(template, propertySet);
        final PropertyMap properties          = PropertyMap.inputTypeToJavaType(securityContext, entityClass, propertySet);
        RelationshipInterface newRelationship = null;

        if (sourceNode == null) {
          errorBuffer.add(entityClass.getSimpleName(), new EmptyPropertyToken(template.getSourceIdProperty()));
        }

        if (targetNode == null) {
          errorBuffer.add(entityClass.getSimpleName(), new EmptyPropertyToken(template.getTargetIdProperty()));
        }

        if (errorBuffer.hasError()) {
          throw new FrameworkException(422, errorBuffer);
        }

        newRelationship = app.create(sourceNode, targetNode, entityClass, properties);

        RestMethodResult result = new RestMethodResult(HttpServletResponse.SC_CREATED);
        if (newRelationship != null) {

          result.addHeader("Location", buildLocationHeader(newRelationship));
        }

        result.serializeAsPrimitiveArray(true);
       
        // finally: return 201 Created
        return result;
      }

      // shouldn't happen
      throw new NotFoundException();
    }
  }

  @Override
  public RestMethodResult doPut(final Map<String, Object> propertySet) throws FrameworkException {
    throw new IllegalPathException();
  }

  public NodeInterface createNode(final Map<String, Object> propertySet) throws FrameworkException {

    if (entityClass != null) {

      final App app                = StructrApp.getInstance(securityContext);
      final PropertyMap properties = PropertyMap.inputTypeToJavaType(securityContext, entityClass, propertySet);

      return app.create(entityClass, properties);
    }

    throw new NotFoundException();
  }

  @Override
  public Resource tryCombineWith(Resource next) throws FrameworkException {

    if (next instanceof UuidResource) {

      TypedIdResource constraint = new TypedIdResource(securityContext, (UuidResource) next, this);

      constraint.configureIdProperty(idProperty);

      return constraint;

    } else if (next instanceof TypeResource) {

      throw new IllegalPathException();
    }

    return super.tryCombineWith(next);
  }

  @Override
  public String getUriPart() {
    return rawType;
  }

  public String getRawType() {
    return rawType;
  }

  @Override
  public Class getEntityClass() {
    return entityClass;
  }

  public void setEntityClass(final Class<? extends GraphObject> type) {
    this.entityClass = type;
  }

  public void setSearchCommandType(final Class<? extends SearchCommand> searchCommand) {
    this.searchCommandType = searchCommand;
  }

  @Override
  public String getResourceSignature() {
    return SchemaHelper.normalizeEntityName(getUriPart());
  }

  @Override
  public boolean isCollectionResource() {
    return true;
  }

  public void collectSearchAttributes(final Query query) throws FrameworkException {

    // first step: extract searchable attributes from request
    extractSearchableAttributes(securityContext, entityClass, request, query);

    // second step: distance search?
    extractDistanceSearch(request, query);
  }

  // ----- private methods -----
  private Relation getRelationshipTemplate() {

    try {

      return (Relation)entityClass.newInstance();

    } catch (Throwable t) {

    }

    return null;
  }

  private NodeInterface identifyStartNode(final Relation template, final Map<String, Object> properties) throws FrameworkException {

    final Property<String> sourceIdProperty = template.getSourceIdProperty();
    final Class sourceType                  = template.getSourceType();
    final Notion notion                     = template.getStartNodeNotion();

    notion.setType(sourceType);

                PropertyKey startNodeIdentifier = notion.getPrimaryPropertyKey();

                if (startNodeIdentifier != null) {

                        Object identifierValue = properties.get(startNodeIdentifier.dbName());

                        properties.remove(sourceIdProperty.dbName());

                        return (NodeInterface)notion.getAdapterForSetter(securityContext).adapt(identifierValue);

                }

    return null;
  }

  private NodeInterface identifyEndNode(final Relation template, final Map<String, Object> properties) throws FrameworkException {

    final Property<String> targetIdProperty = template.getTargetIdProperty();
    final Class targetType                  = template.getTargetType();
    final Notion notion                     = template.getEndNodeNotion();

    notion.setType(targetType);

                final PropertyKey endNodeIdentifier = notion.getPrimaryPropertyKey();
                if (endNodeIdentifier != null) {

                        Object identifierValue = properties.get(endNodeIdentifier.dbName());

                        properties.remove(targetIdProperty.dbName());

                        return (NodeInterface)notion.getAdapterForSetter(securityContext).adapt(identifierValue);

                }

    return null;
  }
}
TOP

Related Classes of org.structr.rest.resource.TypeResource

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.