blob: f0f32278214557b7c3f8a92f69a83fae0bd63f6e [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.usergrid.services;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.usergrid.persistence.EntityRef;
import org.apache.usergrid.persistence.Query;
import org.apache.usergrid.services.ServiceParameter.QueryParameter;
import org.apache.usergrid.services.ServiceResults.Type;
import org.apache.shiro.SecurityUtils;
import static org.apache.commons.lang.StringUtils.isNotBlank;
import static org.apache.usergrid.utils.ListUtils.isEmpty;
import static org.apache.usergrid.utils.ListUtils.last;
public class ServiceRequest {
private static final Logger logger = LoggerFactory.getLogger( ServiceRequest.class );
public static long count = 0;
private final long id = count++;
private final ServiceManager services;
private final ServiceAction action;
private final ServiceRequest parent;
private final EntityRef owner;
private final String serviceName;
private final String path;
private final List<ServiceParameter> parameters;
private final String childPath;
private final boolean returnsTree;
private final boolean returnsInboundConnections;
private final boolean returnsOutboundConnections;
private final ServicePayload payload;
private final List<ServiceParameter> originalParameters;
private final boolean analyzeQueryOnly;
private final boolean returnQuery;
// return results_set, result_entity, new_service, param_list, properties
public ServiceRequest(ServiceManager services, ServiceAction action, String serviceName,
List<ServiceParameter> parameters, ServicePayload payload, boolean returnsTree,
boolean returnsInboundConnections, boolean returnsOutboundConnections,
boolean analyzeQueryOnly, boolean returnQuery) {
this.services = services;
this.action = action;
parent = null;
owner = services.getApplicationRef();
childPath = null;
this.serviceName = serviceName;
path = "/" + serviceName;
this.parameters = parameters;
this.originalParameters = Collections.unmodifiableList( new ArrayList<ServiceParameter>( parameters ) );
this.returnsTree = returnsTree;
this.returnsInboundConnections = returnsInboundConnections;
this.returnsOutboundConnections = returnsOutboundConnections;
this.analyzeQueryOnly = analyzeQueryOnly;
this.returnQuery = returnQuery;
if ( payload == null ) {
payload = new ServicePayload();
}
this.payload = payload;
}
public ServiceRequest( ServiceManager services, ServiceAction action, String serviceName,
List<ServiceParameter> parameters, ServicePayload payload, boolean returnsTree) {
this( services, action, serviceName, parameters, payload, returnsTree, true, true, false, false);
}
public ServiceRequest( ServiceManager services, ServiceAction action, String serviceName,
List<ServiceParameter> parameters, ServicePayload payload ) {
this( services, action, serviceName, parameters, payload, false, true, true, false, false);
}
public ServiceRequest( ServiceRequest parent, EntityRef owner, String path, String childPath, String serviceName,
List<ServiceParameter> parameters ) {
this.services = parent.services;
this.returnsTree = parent.returnsTree;
this.returnsInboundConnections = parent.returnsInboundConnections;
this.returnsOutboundConnections = parent.returnsOutboundConnections;
this.analyzeQueryOnly = parent.analyzeQueryOnly;
this.returnQuery = parent.returnQuery;
this.action = parent.action;
this.payload = parent.payload;
this.parent = parent;
this.owner = owner;
this.serviceName = serviceName;
if ( parameters == null ) {
parameters = new ArrayList<ServiceParameter>();
}
this.parameters = parameters;
this.originalParameters = Collections.unmodifiableList( new ArrayList<ServiceParameter>( parameters ) );
this.path = path;
this.childPath = childPath;
}
public ServiceRequest( ServiceManager services, ServiceAction action, ServiceRequest parent, EntityRef owner,
String path, String childPath, String serviceName, List<ServiceParameter> parameters,
ServicePayload payload, boolean returnsTree, boolean returnsInboundConnections,
boolean returnsOutboundConnections, boolean analyzeQueryOnly,
boolean returnQuery) {
this.services = services;
this.action = action;
this.parent = parent;
this.owner = owner;
this.serviceName = serviceName;
this.path = path;
this.parameters = parameters;
this.originalParameters = Collections.unmodifiableList( new ArrayList<ServiceParameter>( parameters ) );
this.childPath = childPath;
this.returnsTree = returnsTree;
this.returnsInboundConnections = returnsInboundConnections;
this.returnsOutboundConnections = returnsOutboundConnections;
this.analyzeQueryOnly = analyzeQueryOnly;
this.returnQuery = returnQuery;
this.payload = payload;
}
public ServiceRequest( ServiceManager services, ServiceAction action, ServiceRequest parent, EntityRef owner,
String path, String childPath, String serviceName, List<ServiceParameter> parameters,
ServicePayload payload, boolean returnsTree ) {
this(services, action, parent, owner, path, childPath, serviceName, parameters, payload, returnsTree,
true, true, false, false);
}
public static ServiceRequest withPath( ServiceRequest r, String path ) {
return new ServiceRequest( r.services, r.action, r.parent, r.owner, path, r.childPath, r.serviceName,
r.parameters, r.payload, r.returnsTree, r.returnsInboundConnections, r.returnsOutboundConnections,
r.analyzeQueryOnly, r.returnQuery);
}
public static ServiceRequest withChildPath( ServiceRequest r, String childPath ) {
return new ServiceRequest( r.services, r.action, r.parent, r.owner, r.path, childPath, r.serviceName,
r.parameters, r.payload, r.returnsTree, r.returnsInboundConnections, r.returnsOutboundConnections,
r.analyzeQueryOnly, r.returnQuery);
}
public ServiceRequest withPath( String path ) {
return withPath( this, path );
}
public ServiceRequest withChildPath( String childPath ) { return withChildPath( this, childPath ); }
public long getId() {
return id;
}
public String getPath() {
return path;
}
public ServiceAction getAction() {
return action;
}
public ServicePayload getPayload() {
return payload;
}
public ServiceManager getServices() {
return services;
}
public ServiceRequest getParent() {
return parent;
}
public String getServiceName() {
return serviceName;
}
public EntityRef getPreviousOwner() {
if ( parent == null ) {
return null;
}
return parent.getOwner();
}
public ServiceResults execute() throws Exception {
try {
return execute( null );
}
catch ( Exception e ) {
// don't log as error because some exceptions are not actually errors, e.g. resource not found
if (logger.isDebugEnabled()) {
logger.debug(debugString(), e);
}
throw e;
}
}
private String debugString() {
StringBuffer sb = new StringBuffer();
sb.append( "request details:\n " );
sb.append( action );
sb.append( " " );
sb.append( this );
sb.append( "\n payload: " );
sb.append( payload );
sb.append( "\n owner: " );
sb.append( owner );
sb.append( "\n principal: " );
sb.append( SecurityUtils.getSubject().getPrincipal() );
return sb.toString();
}
public ServiceContext getAppContext() throws Exception {
Service s = services.getService( serviceName );
return s.getContext( action,this,null,payload );
}
public ServiceResults execute( ServiceResults previousResults ) throws Exception {
// initServiceName();
ServiceResults results = null;
Service s = services.getService( serviceName );
if ( s != null ) {
results = s.invoke( action, this, previousResults, payload );
if ( ( results != null ) && results.hasMoreRequests() ) {
results = invokeMultiple( results );
}
}
if ( results == null ) {
results = new ServiceResults( null, this, previousResults, null, Type.GENERIC, null, null, null );
}
return results;
}
private ServiceResults invokeMultiple( ServiceResults previousResults ) throws Exception {
List<ServiceRequest> requests = previousResults.getNextRequests();
if ( returnsTree ) {
for ( ServiceRequest request : requests ) {
ServiceResults rs = request.execute( previousResults );
if ( rs != null ) {
previousResults.setChildResults( rs );
}
}
return previousResults;
}
else {
ServiceResults aggregate_results = null;
for ( ServiceRequest request : requests ) {
ServiceResults rs = request.execute( previousResults );
if ( rs != null ) {
if ( aggregate_results == null ) {
aggregate_results = rs;
}
else {
aggregate_results.merge( rs );
}
}
}
return aggregate_results;
}
}
public List<ServiceParameter> getParameters() {
return parameters;
}
public boolean hasParameters() {
return !isEmpty( parameters );
}
public EntityRef getOwner() {
return owner;
}
public Query getLastQuery() {
if ( !isEmpty( parameters ) ) {
return last( parameters ).getQuery();
}
return null;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
if ( serviceName != null ) {
sb.append( "/" );
sb.append( serviceName );
}
for ( int i = 0; i < parameters.size(); i++ ) {
ServiceParameter p = parameters.get( i );
if ( p instanceof QueryParameter ) {
if ( i == ( parameters.size() - 1 ) ) {
sb.append( '?' );
}
else {
sb.append( ';' );
}
boolean has_prev_param = false;
String q = p.toString();
if ( isNotBlank( q ) ) {
try {
sb.append("ql=").append(URLEncoder.encode(q, "UTF-8"));
}
catch ( UnsupportedEncodingException e ) {
logger.error( "Unable to encode url", e );
}
has_prev_param = true;
}
int limit = p.getQuery().getLimit();
if ( limit != Query.DEFAULT_LIMIT ) {
if ( has_prev_param ) {
sb.append( '&' );
}
sb.append("limit=").append(limit);
has_prev_param = true;
}
if ( p.getQuery().getStartResult() != null ) {
if ( has_prev_param ) {
sb.append( '&' );
}
sb.append("start=").append(p.getQuery().getStartResult());
has_prev_param = true;
}
}
else {
sb.append( '/' );
sb.append( p.toString() );
}
}
return sb.toString();
}
public String getChildPath() {
return childPath;
}
public boolean isReturnsTree() { return returnsTree; }
public boolean isReturnsInboundConnections() { return returnsInboundConnections; }
public boolean isReturnsOutboundConnections() { return returnsOutboundConnections; }
public List<ServiceParameter> getOriginalParameters() {
return originalParameters;
}
public boolean isAnalyzeQueryOnly(){
return analyzeQueryOnly;
}
public boolean shouldReturnQuery(){
return returnQuery;
}
}