Package org.structr.rest.servlet

Source Code of org.structr.rest.servlet.ResourceHelper

/**
* 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.servlet;


import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.structr.common.SecurityContext;
import org.structr.common.error.FrameworkException;
import org.structr.core.Services;
import org.structr.core.Value;
import org.structr.core.ViewTransformation;
import org.structr.core.app.StructrApp;
import org.structr.core.property.PropertyKey;
import org.structr.rest.exception.IllegalPathException;
import org.structr.rest.exception.NoResultsException;
import org.structr.rest.exception.NotFoundException;
import org.structr.rest.resource.Resource;
import org.structr.rest.resource.TransformationResource;
import org.structr.rest.resource.ViewFilterResource;

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

/**
* Helper class for parsing and optimizing the resource path
*
@author Axel Morgner
*/
public class ResourceHelper {

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

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

  /**
   * Parse the request path and match with possible resource patterns
   *
   * @param securityContext
   * @param request
   * @param resourceMap
   * @param propertyView
   * @param defaultIdProperty
   * @return resourceChain
   * @throws FrameworkException
   */
  public static List<Resource> parsePath(final SecurityContext securityContext, final HttpServletRequest request, final Map<Pattern, Class<? extends Resource>> resourceMap, final Value<String> propertyView, final PropertyKey defaultIdProperty) throws FrameworkException {

    final String path = request.getPathInfo();

    // intercept empty path and send 204 No Content
    if (!StringUtils.isNotBlank(path)) {

      throw new NoResultsException();
    }

    // 1.: split request path into URI parts
    final String[] pathParts = path.split("[/]+");

    // 2.: create container for resource constraints
    final Set<String> propertyViews    = Services.getInstance().getConfigurationProvider().getPropertyViews();
    final List<Resource> resourceChain = new ArrayList<>(pathParts.length);

    // 3.: try to assign resource constraints for each URI part
    for (int i = 0; i < pathParts.length; i++) {

      // eliminate empty strings
      final String part = pathParts[i].trim();

      if (part.length() > 0) {

        boolean found = false;
       
        // check views first
        if (propertyViews.contains(part)) {
       
          Resource resource = new ViewFilterResource();
          resource.checkAndConfigure(part, securityContext, request);
          resource.configureIdProperty(defaultIdProperty);
          resource.configurePropertyView(propertyView);
         
          resourceChain.add(resource);
         
          // mark this part as successfully parsed
          found = true;
         
        } else {

          // look for matching pattern
          for (Map.Entry<Pattern, Class<? extends Resource>> entry : resourceMap.entrySet()) {

            Pattern pattern = entry.getKey();
            Matcher matcher = pattern.matcher(pathParts[i]);

            if (matcher.matches()) {

              Class<? extends Resource> type = entry.getValue();
              Resource resource              = null;

              try {

                // instantiate resource constraint
                resource = type.newInstance();
              } catch (Throwable t) {

                logger.log(Level.WARNING, "Error instantiating resource class", t);

              }

              if (resource != null) {

                // set security context
                resource.setSecurityContext(securityContext);

                if (resource.checkAndConfigure(part, securityContext, request)) {

                  logger.log(Level.FINE, "{0} matched, adding resource of type {1} for part {2}", new Object[] { matcher.pattern(), type.getName(),
                    part });

                  // allow constraint to modify context
                  resource.configurePropertyView(propertyView);
                  resource.configureIdProperty(defaultIdProperty);

                  // add constraint and go on
                  resourceChain.add(resource);

                  found = true;

                  // first match wins, so choose priority wisely ;)
                  break;

                }
              }

            }
          }
        }

        if (!found) {

          throw new NotFoundException();
        }

      }
    }

    return resourceChain;

  }

  /**
   * Optimize the resource chain by trying to combine two resources to a new one
   *
   * @param resourceChain
   * @param defaultIdProperty
   * @return finalResource
   * @throws FrameworkException
   */
  public static Resource optimizeNestedResourceChain(final List<Resource> resourceChain, final PropertyKey defaultIdProperty) throws FrameworkException {

    ViewFilterResource view = null;
    int num                 = resourceChain.size();
    boolean found           = false;

    do {

      for (Iterator<Resource> it = resourceChain.iterator(); it.hasNext(); ) {

        Resource constr = it.next();

        if (constr instanceof ViewFilterResource) {

          view = (ViewFilterResource) constr;

          it.remove();

        }

      }

      found = false;

      try {

        for (int i = 0; i < num; i++) {

          Resource firstElement       = resourceChain.get(i);
          Resource secondElement      = resourceChain.get(i + 1);
          Resource combinedConstraint = firstElement.tryCombineWith(secondElement);

          if (combinedConstraint != null) {

            // remove source constraints
            resourceChain.remove(firstElement);
            resourceChain.remove(secondElement);

            // add combined constraint
            resourceChain.add(i, combinedConstraint);

            // signal success
            found = true;

          }

        }

      } catch (Throwable t) {

        // ignore exceptions thrown here
      }

    } while (found);

    if (resourceChain.size() == 1) {

      Resource finalResource = resourceChain.get(0);

      if (view != null) {

        finalResource = finalResource.tryCombineWith(view);
      }
     
      if (finalResource == null) {
        // fall back to original resource
        finalResource = resourceChain.get(0);
      }

      // inform final constraint about the configured ID property
      finalResource.configureIdProperty(defaultIdProperty);

      return finalResource;

    }

    throw new IllegalPathException();

  }

  /**
   * Apply view transformation on final resource, if any
   *
   * @param request
   * @param securityContext
   * @param finalResource
   * @param propertyView
   * @return transformedResource
   * @throws FrameworkException
   */
  public static Resource applyViewTransformation(final HttpServletRequest request, final SecurityContext securityContext, final Resource finalResource, final Value<String> propertyView) throws FrameworkException {

    Resource transformedResource = finalResource;

    // add view transformation
    Class type = finalResource.getEntityClass();
    if (type != null) {
     
      ViewTransformation transformation = StructrApp.getConfiguration().getViewTransformation(type, propertyView.get(securityContext));
      if (transformation != null) {
       
        transformedResource = transformedResource.tryCombineWith(new TransformationResource(securityContext, transformation));
      }
    }

    return transformedResource;
  }
 
}
TOP

Related Classes of org.structr.rest.servlet.ResourceHelper

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.