org.apache.wink.server.internal.handlers.SearchResult Maven / Gradle / Ivy
/*******************************************************************************
* 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.wink.server.internal.handlers;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.PathSegment;
import javax.ws.rs.core.UriInfo;
import org.apache.wink.common.internal.MultivaluedMapImpl;
import org.apache.wink.common.internal.utils.UriHelper;
import org.apache.wink.server.internal.registry.MethodRecord;
import org.apache.wink.server.internal.registry.ResourceInstance;
import org.apache.wink.server.internal.registry.SubResourceLocatorRecord;
import org.apache.wink.server.internal.registry.SubResourceMethodRecord;
/**
* Stores the result of searching for a resource method to dispatch a request to
*/
public class SearchResult {
private boolean found;
private WebApplicationException error;
private ResourceInstance resource;
private MethodRecord method;
private Object[] invocationParameters;
private AccumulatedData data;
private UriInfo uriInfo;
public static class AccumulatedData implements Cloneable {
private UriInfo uriInfo;
private MultivaluedMap matchedVariables;
private MultivaluedMap> matchedVariablesPathSegments;
private LinkedList> matchedURIs;
private LinkedList matchedResources;
public AccumulatedData(UriInfo uriInfo) {
this.uriInfo = uriInfo;
}
@Override
@SuppressWarnings("unchecked")
public AccumulatedData clone() {
AccumulatedData clone;
try {
clone = (AccumulatedData)super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
clone.matchedVariables = MultivaluedMapImpl.clone(getMatchedVariables());
clone.matchedVariablesPathSegments =
MultivaluedMapImpl.clone(getMatchedVariablesPathSegments());
clone.matchedURIs = (LinkedList>)getMatchedURIs().clone();
clone.matchedResources = (LinkedList)getMatchedResources().clone();
return clone;
}
public void setMatchedVariables(MultivaluedMap matchedVariables) {
this.matchedVariables = matchedVariables;
}
public void setMatchedURIs(LinkedList> matchedURIs) {
this.matchedURIs = matchedURIs;
}
public void setMatchedResources(LinkedList matchedResources) {
this.matchedResources = matchedResources;
}
public MultivaluedMap getMatchedVariables() {
if (matchedVariables == null) {
matchedVariables = new MultivaluedMapImpl();
}
return matchedVariables;
}
public MultivaluedMap> getMatchedVariablesPathSegments() {
if (matchedVariablesPathSegments == null) {
matchedVariablesPathSegments = new MultivaluedMapImpl>();
}
return matchedVariablesPathSegments;
}
public LinkedList getMatchedResources() {
if (matchedResources == null) {
matchedResources = new LinkedList();
}
return matchedResources;
}
public LinkedList> getMatchedURIs() {
if (matchedURIs == null) {
matchedURIs = new LinkedList>();
}
return matchedURIs;
}
/**
* Used for providing the info for the {@link UriInfo#getMatchedURIs()}
* method.
*
* @param uri the uri that was used for the matching is stripped from
* any matrix parameters
* @return the number of segments of the input uri
*/
public int addMatchedURI(String uri) {
// get all the segments of the original request (which include the
// matrix parameters)
List segments = uriInfo.getPathSegments(false);
// count the number of segments in input uri
int count = uri.equals("") ? 0 : UriHelper.parsePath(uri).size(); //$NON-NLS-1$
// get the offset of the provided uri from the complete request path
int offset = calculateUriOffset();
// add the uri segments (including any matrix parameters) by
// obtaining a sub list from the the complete request segments
addMatchedURI(segments, offset, count);
return count;
}
/**
* Used to calculate the number of URI segments already matched.
*
* @return the offset past the URI segments already matched
*/
public int calculateUriOffset() {
int offset = 0;
if (getMatchedURIs().size() > 0) {
// the first uri in the "matched uri's" list always reflects all
// the path segments
// that were matched until now, from the beginning of the
// complete request uri
List firstMatchedUri = getMatchedURIs().getFirst();
offset = firstMatchedUri.size();
// we need to skip all empty string as path segments that were
// added
// because of matches to @Path("") and @Path("/"), so decrease
// the
// offset by the number of empty segments
for (PathSegment segment : firstMatchedUri) {
if (segment.getPath().equals("")) { //$NON-NLS-1$
--offset;
}
}
}
return offset;
}
private void addMatchedURI(List segments, int offset, int count) {
// obtain the sub list of uri segments from the the complete request
// segments
int toIndex = offset + count;
List subListSegments = segments.subList(offset, toIndex);
if (subListSegments.isEmpty()) {
// the sublist may be empty if the count is 0. this can happen
// if the given uri was an empty string (which itself can happen
// if the resource/sub-resource are annotated with @Path("") or
// @Path("/").
subListSegments = UriHelper.parsePath(""); //$NON-NLS-1$
}
LinkedList> matchedURIs = getMatchedURIs();
if (matchedURIs.size() == 0) {
// if it's the first uri, simply add it
matchedURIs.add(subListSegments);
return;
}
// need to concatenate the sub list of segments to the first uri in
// the list of matched uri's
List currentMatchedUri = matchedURIs.getFirst();
List newMatchedUri =
new ArrayList(currentMatchedUri.size() + subListSegments.size());
newMatchedUri.addAll(currentMatchedUri);
newMatchedUri.addAll(subListSegments);
matchedURIs.addFirst(newMatchedUri);
}
public ResourceInstance getResource() {
return matchedResources.getFirst();
}
}
public enum MethodType {
ResourceMethod, SubResourceMethod, SubResourceLocator;
}
@Override
public String toString() {
return String.format("Found: %s, Resource: %s, Method: %s, Error: %s", //$NON-NLS-1$
found,
resource,
method,
error);
}
public SearchResult(ResourceInstance resource, UriInfo uriInfo) {
this(false);
this.uriInfo = uriInfo;
getData().getMatchedResources().addFirst(resource);
}
public SearchResult(WebApplicationException error) {
this(false);
this.error = error;
}
private SearchResult(boolean found) {
this.found = found;
this.error = null;
this.uriInfo = null;
}
public ResourceInstance getResource() {
if (getData().getMatchedResources().isEmpty()) {
return null;
}
return getData().getMatchedResources().getFirst();
}
public MethodRecord getMethod() {
return method;
}
public SearchResult setMethod(MethodRecord method) {
this.method = method;
return this;
}
public MethodType getMethodType() {
if (method instanceof SubResourceMethodRecord) {
return MethodType.SubResourceMethod;
}
if (method instanceof SubResourceLocatorRecord) {
return MethodType.SubResourceLocator;
}
return MethodType.ResourceMethod;
}
public Object[] getInvocationParameters() {
return invocationParameters;
}
public void setInvocationParameters(Object[] invocationParameters) {
this.invocationParameters = invocationParameters;
}
public WebApplicationException getError() {
return error;
}
public SearchResult setError(WebApplicationException error) {
this.error = error;
if (error != null) {
this.found = false;
}
return this;
}
public boolean isError() {
return error != null;
}
public SearchResult setFound(boolean found) {
this.found = found;
this.error = null;
return this;
}
public boolean isFound() {
return this.found;
}
public AccumulatedData getData() {
if (data == null) {
data = new AccumulatedData(uriInfo);
}
return data;
}
public void setData(AccumulatedData data) {
this.data = data;
}
}