Package org.structr.web.datasource

Source Code of org.structr.web.datasource.RestDataSource$ThreadLocalPropertyView

/**
* 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 Affero 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 Affero General Public License
* along with Structr.  If not, see <http://www.gnu.org/licenses/>.
*/
package org.structr.web.datasource;

import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.apache.commons.collections.iterators.IteratorEnumeration;
import org.apache.commons.lang3.StringUtils;
import org.structr.common.PagingHelper;
import org.structr.common.PropertyView;
import org.structr.common.SecurityContext;
import org.structr.common.error.FrameworkException;
import org.structr.core.GraphObject;
import org.structr.core.Result;
import org.structr.core.Value;
import org.structr.core.app.StructrApp;
import org.structr.core.entity.AbstractNode;
import org.structr.core.graph.NodeFactory;
import org.structr.core.property.PropertyKey;
import org.structr.rest.ResourceProvider;
import org.structr.rest.resource.Resource;
import org.structr.rest.servlet.JsonRestServlet;
import org.structr.rest.servlet.ResourceHelper;
import org.structr.web.common.GraphDataSource;
import org.structr.web.common.RenderContext;
import org.structr.web.common.UiResourceProvider;
import org.structr.web.entity.dom.DOMNode;

/**
* List data source equivalent to a rest resource.
*
* TODO: This method uses code from the {@link JsonRestServlet} which should be
* encapsulated and re-used here
*
*/
public class RestDataSource implements GraphDataSource<List<GraphObject>> {

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

  @Override
  public List<GraphObject> getData(final SecurityContext securityContext, final RenderContext renderContext, AbstractNode referenceNode) throws FrameworkException {

    final String restQuery = ((DOMNode) referenceNode).getPropertyWithVariableReplacement(securityContext, renderContext, DOMNode.restQuery);
    if (restQuery == null || restQuery.isEmpty()) {
      return Collections.EMPTY_LIST;
    }

    return getData(securityContext, renderContext, restQuery);
  }

  // FIXME: this method is needed by the websocket search command because there is no reference node for the above method
  public List<GraphObject> getData(final SecurityContext securityContext, final RenderContext renderContext, final String restQuery) throws FrameworkException {

    Map<Pattern, Class<? extends Resource>> resourceMap = new LinkedHashMap<>();

    ResourceProvider resourceProvider = renderContext == null ? null : renderContext.getResourceProvider();
    if (resourceProvider == null) {
      try {
        resourceProvider = UiResourceProvider.class.newInstance();
      } catch (Throwable t) {
        logger.log(Level.SEVERE, "Couldn't establish a resource provider", t);
        return Collections.EMPTY_LIST;
      }
    }

    // inject resources
    resourceMap.putAll(resourceProvider.getResources());

    Value<String> propertyView = new ThreadLocalPropertyView();
    propertyView.set(securityContext, PropertyView.Ui);

    // initialize variables
    // mimic HTTP request
    HttpServletRequest request = new HttpServletRequestWrapper(renderContext == null ? securityContext.getRequest() : renderContext.getRequest()) {

      @Override
      public Enumeration<String> getParameterNames() {
        return new IteratorEnumeration(getParameterMap().keySet().iterator());
      }

      @Override
      public String getParameter(String key) {
        String[] p = getParameterMap().get(key);
        return p != null ? p[0] : null;
      }

      @Override
      public Map<String, String[]> getParameterMap() {
        String[] parts = StringUtils.split(getQueryString(), "&");
        Map<String, String[]> parameterMap = new HashMap();
        for (String p : parts) {
          String[] kv = StringUtils.split(p, "=");
          if (kv.length > 1) {
            parameterMap.put(kv[0], new String[]{kv[1]});
          }
        }
        return parameterMap;
      }

      @Override
      public String getQueryString() {
        return StringUtils.substringAfter(restQuery, "?");
      }

      @Override
      public String getPathInfo() {
        return StringUtils.substringBefore(restQuery, "?");
      }

      @Override
      public StringBuffer getRequestURL() {
        return new StringBuffer(restQuery);
      }
    };

    // update request in security context
    securityContext.setRequest(request);

    //HttpServletResponse response = renderContext.getResponse();
    Resource resource = ResourceHelper.applyViewTransformation(request, securityContext, ResourceHelper.optimizeNestedResourceChain(ResourceHelper.parsePath(securityContext, request, resourceMap, propertyView, GraphObject.id), GraphObject.id), propertyView);

    // TODO: decide if we need to rest the REST request here
    //securityContext.checkResourceAccess(request, resource.getResourceSignature(), resource.getGrant(request, response), PropertyView.Ui);
    // add sorting & paging
    String pageSizeParameter = request.getParameter(JsonRestServlet.REQUEST_PARAMETER_PAGE_SIZE);
    String pageParameter = request.getParameter(JsonRestServlet.REQUEST_PARAMETER_PAGE_NUMBER);
    String offsetId = request.getParameter(JsonRestServlet.REQUEST_PARAMETER_OFFSET_ID);
    String sortOrder = request.getParameter(JsonRestServlet.REQUEST_PARAMETER_SORT_ORDER);
    String sortKeyName = request.getParameter(JsonRestServlet.REQUEST_PARAMETER_SORT_KEY);
    boolean sortDescending = (sortOrder != null && "desc".equals(sortOrder.toLowerCase()));
    int pageSize = parseInt(pageSizeParameter, NodeFactory.DEFAULT_PAGE_SIZE);
    int page = parseInt(pageParameter, NodeFactory.DEFAULT_PAGE);
    PropertyKey sortKey = null;

    // set sort key
    if (sortKeyName != null) {

      Class<? extends GraphObject> type = resource.getEntityClass();
      if (type == null) {

        // fallback to default implementation
        // if no type can be determined
        type = AbstractNode.class;

      }
      sortKey = StructrApp.getConfiguration().getPropertyKeyForDatabaseName(type, sortKeyName);
    }

    // do action
    Result result = resource.doGet(sortKey, sortDescending, pageSize, page, offsetId);
    result.setIsCollection(resource.isCollectionResource());
    result.setIsPrimitiveArray(resource.isPrimitiveArray());

    //Integer rawResultCount = (Integer) Services.getAttribute(NodeFactory.RAW_RESULT_COUNT + Thread.currentThread().getId());
    PagingHelper.addPagingParameter(result, pageSize, page);

    List<GraphObject> res = result.getResults();

    if (renderContext != null) {
      renderContext.setResult(result);
    }

    return res != null ? res : Collections.EMPTY_LIST;

  }

  /**
   * Tries to parse the given String to an int value, returning
   * defaultValue on error.
   *
   * @param value the source String to parse
   * @param defaultValue the default value that will be returned when parsing fails
   * @return the parsed value or the given default value when parsing fails
   */
  private static int parseInt(String value, int defaultValue) {

    if (value == null) {

      return defaultValue;

    }

    try {
      return Integer.parseInt(value);
    } catch (Throwable ignore) {}

    return defaultValue;
  }

  private static class ThreadLocalPropertyView extends ThreadLocal<String> implements Value<String> {

    @Override
    protected String initialValue() {
      return PropertyView.Ui;
    }

    @Override
    public void set(SecurityContext securityContext, String value) {
      set(value);
    }

    @Override
    public String get(SecurityContext securityContext) {
      return get();
    }
  }



}
TOP

Related Classes of org.structr.web.datasource.RestDataSource$ThreadLocalPropertyView

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.