org.apache.openjpa.persistence.jest.AbstractCommand Maven / Gradle / Ivy
The newest version!
/*
* 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.openjpa.persistence.jest;
import static java.net.HttpURLConnection.HTTP_BAD_REQUEST;
import static org.apache.openjpa.persistence.jest.Constants.QUALIFIER_FORMAT;
import static org.apache.openjpa.persistence.jest.Constants.QUALIFIER_PLAN;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.openjpa.enhance.PersistenceCapable;
import org.apache.openjpa.kernel.BrokerImpl;
import org.apache.openjpa.kernel.OpenJPAStateManager;
import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.persistence.FetchPlan;
import org.apache.openjpa.persistence.JPAFacadeHelper;
import org.apache.openjpa.persistence.OpenJPAEntityManager;
import org.apache.openjpa.persistence.OpenJPAQuery;
/**
* The abstract base class for all commands available to JEST.
*
* @author Pinaki Poddar
*
*/
abstract class AbstractCommand implements JESTCommand {
public static final char EQUAL = '=';
public static final String PATH_SEPARATOR = "/";
public static final Collection EMPTY_LIST = Collections.emptySet();
protected ObjectFormatter> _formatter;
private Map _qualifiers = new HashMap<>();
private Map _args = new HashMap<>();
private Map _margs = new HashMap<>();
protected final JPAServletContext _ctx;
private static PrototypeFactory> _formatterFactory =
new PrototypeFactory<>();
protected static Localizer _loc = Localizer.forPackage(AbstractCommand.class);
static {
_formatterFactory.register(Format.xml, XMLFormatter.class);
_formatterFactory.register(Format.json, JSONObjectFormatter.class);
}
protected AbstractCommand(JPAServletContext ctx) {
_ctx = ctx;
}
@Override
public JPAServletContext getExecutionContext() {
return _ctx;
}
public String getMandatoryArgument(String key) {
return get(key, _margs);
}
@Override
public String getArgument(String key) {
return get(key, _args);
}
@Override
public boolean hasArgument(String key) {
return has(key, _args);
}
@Override
public Map getArguments() {
return _args;
}
@Override
public String getQualifier(String key) {
return get(key, _qualifiers);
}
@Override
public boolean hasQualifier(String key) {
return has(key, _qualifiers);
}
protected boolean isBooleanQualifier(String key) {
if (hasQualifier(key)) {
Object value = getQualifier(key);
return value == null || "true".equalsIgnoreCase(value.toString());
}
return false;
}
@Override
public Map getQualifiers() {
return _qualifiers;
}
/**
* Parses HTTP Request for the qualifier and argument of a command.
*
* Each servlet path segment, except the first (which is the command name itself), is a qualifier.
* Each qualifier can be either a key or a key-value pair separated by a = sign.
*
* Each request parameter key-value pair is an argument. A concrete command may specify mandatory
* arguments (e.g. type
must be mandatory argument for find
command,
* or q
for query
. The mandatory arguments, if any, are not captured
* in the argument list.
*
* The qualifiers and arguments are immutable after parse.
*/
@Override
public void parse() throws ProcessingException {
HttpServletRequest request = _ctx.getRequest();
String path = request.getPathInfo();
if (path != null) {
path = path.substring(1);
String[] segments = path.split(PATH_SEPARATOR);
for (int i = 1; i < segments.length; i++) {
String segment = segments[i];
int idx = segment.indexOf(EQUAL);
if (idx == -1) {
_qualifiers.put(segment, null);
} else {
_qualifiers.put(segment.substring(0, idx), segment.substring(idx+1));
}
}
}
_qualifiers = Collections.unmodifiableMap(_qualifiers);
Enumeration> names = request.getParameterNames();
Collection mandatoryArgs = getMandatoryArguments();
while (names.hasMoreElements()) {
String key = names.nextElement().toString();
if (key.startsWith("dojo.")) continue;
put(key, request.getParameter(key), mandatoryArgs.contains(key) ? _margs : _args);
}
_args = Collections.unmodifiableMap(_args);
_margs = Collections.unmodifiableMap(_margs);
validate();
}
/**
* Gets the mandatory arguments.
*
* @return empty list by default.
*/
protected Collection getMandatoryArguments() {
return EMPTY_LIST;
}
/**
* Gets the minimum number of arguments excluding the mandatory arguments.
*
* @return zero by default.
*/
protected int getMinimumArguments() {
return 0;
}
/**
* Gets the maximum number of arguments excluding the mandatory arguments.
*
* @return Integer.MAX_VALUE by default.
*/
protected int getMaximumArguments() {
return Integer.MAX_VALUE;
}
protected Format getDefaultFormat() {
return Format.xml;
}
/**
* Gets the valid qualifiers.
*
* @return empty list by default.
*/
protected Collection getValidQualifiers() {
return EMPTY_LIST;
}
/**
* Called post-parse to validate this command has requisite qualifiers and arguments.
*/
protected void validate() {
HttpServletRequest request = _ctx.getRequest();
Collection validQualifiers = getValidQualifiers();
for (String key : _qualifiers.keySet()) {
if (!validQualifiers.contains(key)) {
throw new ProcessingException(_ctx,_loc.get("parse-invalid-qualifier", this, key, validQualifiers),
HTTP_BAD_REQUEST);
}
}
Collection mandatoryArgs = getMandatoryArguments();
for (String key : mandatoryArgs) {
if (request.getParameter(key) == null) {
throw new ProcessingException(_ctx, _loc.get("parse-missing-mandatory-argument", this, key,
request.getParameterMap().keySet()), HTTP_BAD_REQUEST);
}
}
if (_args.size() < getMinimumArguments()) {
throw new ProcessingException(_ctx, _loc.get("parse-less-argument", this, _args.keySet(),
getMinimumArguments()), HTTP_BAD_REQUEST);
}
if (_args.size() > getMaximumArguments()) {
throw new ProcessingException(_ctx, _loc.get("parse-less-argument", this, _args.keySet(),
getMinimumArguments()), HTTP_BAD_REQUEST);
}
}
private String get(String key, Map map) {
return map.get(key);
}
private String put(String key, String value, Map map) {
return map.put(key, value);
}
private boolean has(String key, Map map) {
return map.containsKey(key);
}
public ObjectFormatter> getObjectFormatter() {
if (_formatter == null) {
String rformat = getQualifier(QUALIFIER_FORMAT);
Format format = null;
if (rformat == null) {
format = getDefaultFormat();
} else {
try {
format = Format.valueOf(rformat);
} catch (Exception e) {
throw new ProcessingException(_ctx, _loc.get("format-not-supported", new Object[]{format,
_ctx.getRequest().getPathInfo(), _formatterFactory.getRegisteredKeys()}), HTTP_BAD_REQUEST);
}
}
_formatter = _formatterFactory.newInstance(format);
if (_formatter == null) {
throw new ProcessingException(_ctx, _loc.get("format-not-supported", new Object[]{format,
_ctx.getRequest().getPathInfo(), _formatterFactory.getRegisteredKeys()}), HTTP_BAD_REQUEST);
}
}
return _formatter;
}
protected OpenJPAStateManager toStateManager(Object obj) {
if (obj instanceof OpenJPAStateManager)
return (OpenJPAStateManager)obj;
if (obj instanceof PersistenceCapable) {
return (OpenJPAStateManager)((PersistenceCapable)obj).pcGetStateManager();
}
return null;
}
protected List toStateManager(Collection> objects) {
List sms = new ArrayList<>();
for (Object o : objects) {
OpenJPAStateManager sm = toStateManager(o);
if (sm != null) sms.add(sm);
}
return sms;
}
protected void pushFetchPlan(Object target) {
if (!hasQualifier(QUALIFIER_PLAN))
return;
OpenJPAEntityManager em = _ctx.getPersistenceContext();
FetchPlan plan = em.pushFetchPlan();
BrokerImpl broker = (BrokerImpl)JPAFacadeHelper.toBroker(em);
if (target instanceof OpenJPAEntityManager) {
broker.setCacheFinderQuery(false);
} else if (target instanceof OpenJPAQuery) {
broker.setCachePreparedQuery(false);
}
String[] plans = getQualifier(QUALIFIER_PLAN).split(",");
for (String p : plans) {
p = p.trim();
if (p.charAt(0) == '-') {
plan.removeFetchGroup(p.substring(1));
} else {
plan.addFetchGroup(p);
}
}
}
protected void popFetchPlan(boolean finder) {
if (!hasQualifier(QUALIFIER_PLAN))
return;
OpenJPAEntityManager em = _ctx.getPersistenceContext();
BrokerImpl broker = (BrokerImpl)JPAFacadeHelper.toBroker(em);
if (finder) {
broker.setCacheFinderQuery(false);
} else {
broker.setCachePreparedQuery(false);
}
}
protected void debug(HttpServletRequest request, HttpServletResponse response, JPAServletContext ctx)
throws IOException {
response.setContentType(Constants.MIME_TYPE_PLAIN);
PrintWriter writer = response.getWriter();
writer.println("URI = [" + request.getRequestURI() + "]");
writer.println("URL = [" + request.getRequestURL() + "]");
writer.println("Servlet Path = [" + request.getServletPath() + "]"); // this is one we need
writer.println("Context Path = [" + request.getContextPath() + "]");
writer.println("Translated Path = [" + request.getPathTranslated() + "]");// not decoded
writer.println("Path Info = [" + request.getPathInfo() + "]");// decoded
String query = request.getQueryString();
if (query != null) {
query = URLDecoder.decode(request.getQueryString(),"UTF-8");
}
writer.println("Query = [" + query + "]"); // and this one
int i = 0;
for (Map.Entry e : _qualifiers.entrySet()) {
writer.println("Qualifier [" + i + "] = [" + e.getKey() + ": " + e.getValue() + "]");
i++;
}
i = 0;
for (Map.Entry e : _args.entrySet()) {
writer.println("Parameter [" + i + "] = [" + e.getKey() + ": " + e.getValue() + "]");
i++;
}
}
}