/**
* 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.qpid.server.management.plugin.servlet.rest;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.Writer;
import java.security.AccessControlException;
import java.util.*;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQSecurityException;
import org.apache.qpid.server.model.*;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
public class RestServlet extends AbstractServlet
{
private static final Logger LOGGER = Logger.getLogger(RestServlet.class);
/**
* An initialization parameter to specify hierarchy
*/
private static final String HIERARCHY_INIT_PARAMETER = "hierarchy";
public static final String DEPTH_PARAM = "depth";
public static final String SORT_PARAM = "sort";
public static final Set RESERVED_PARAMS = new HashSet(Arrays.asList(DEPTH_PARAM, SORT_PARAM));
private Class extends ConfiguredObject>[] _hierarchy;
private final ConfiguredObjectToMapConverter _objectConverter = new ConfiguredObjectToMapConverter();
private final boolean _hierarchyInitializationRequired;
public RestServlet()
{
super();
_hierarchyInitializationRequired = true;
}
public RestServlet(Class extends ConfiguredObject>... hierarchy)
{
super();
_hierarchy = hierarchy;
_hierarchyInitializationRequired = false;
}
@Override
public void init() throws ServletException
{
super.init();
if (_hierarchyInitializationRequired)
{
doInitialization();
}
}
@SuppressWarnings("unchecked")
private void doInitialization() throws ServletException
{
ServletConfig config = getServletConfig();
String hierarchy = config.getInitParameter(HIERARCHY_INIT_PARAMETER);
if (hierarchy != null && !"".equals(hierarchy))
{
List> classes = new ArrayList>();
String[] hierarchyItems = hierarchy.split(",");
for (String item : hierarchyItems)
{
Class> itemClass = null;
try
{
itemClass = Class.forName(item);
}
catch (ClassNotFoundException e)
{
try
{
itemClass = Class.forName("org.apache.qpid.server.model." + item);
}
catch (ClassNotFoundException e1)
{
throw new ServletException("Unknown configured object class '" + item
+ "' is specified in hierarchy for " + config.getServletName());
}
}
Class extends ConfiguredObject> clazz = (Class extends ConfiguredObject>)itemClass;
classes.add(clazz);
}
Class extends ConfiguredObject>[] hierachyClasses = (Class extends ConfiguredObject>[])new Class[classes.size()];
_hierarchy = classes.toArray(hierachyClasses);
}
else
{
_hierarchy = (Class extends ConfiguredObject>[])new Class[0];
}
}
protected Collection getObjects(HttpServletRequest request)
{
List names = new ArrayList();
if(request.getPathInfo() != null && request.getPathInfo().length()>0)
{
String path = request.getPathInfo().substring(1);
names.addAll(Arrays.asList(path.split("/")));
if(names.size() > _hierarchy.length)
{
throw new IllegalArgumentException("Too many entries in path");
}
}
Collection parents = Collections.singleton((ConfiguredObject) getBroker());
Collection children = new ArrayList();
Map, String> filters =
new HashMap, String>();
for(int i = 0; i < _hierarchy.length; i++)
{
if(i == 0 || Model.getInstance().getChildTypes(_hierarchy[i - 1]).contains(_hierarchy[i]))
{
for(ConfiguredObject parent : parents)
{
if(names.size() > i
&& names.get(i) != null
&& !names.get(i).equals("*")
&& names.get(i).trim().length() != 0)
{
for(ConfiguredObject child : parent.getChildren(_hierarchy[i]))
{
if(child.getName().equals(names.get(i)))
{
children.add(child);
}
}
}
else
{
children.addAll(parent.getChildren(_hierarchy[i]));
}
}
}
else
{
children = parents;
if(names.size() > i
&& names.get(i) != null
&& !names.get(i).equals("*")
&& names.get(i).trim().length() != 0)
{
filters.put(_hierarchy[i], names.get(i));
}
}
parents = children;
children = new ArrayList();
}
if(!filters.isEmpty())
{
Collection potentials = parents;
parents = new ArrayList();
for(ConfiguredObject o : potentials)
{
boolean match = true;
for(Map.Entry, String> entry : filters.entrySet())
{
Collection extends ConfiguredObject> ancestors =
getAncestors(getConfiguredClass(),entry.getKey(), o);
match = false;
for(ConfiguredObject ancestor : ancestors)
{
if(ancestor.getName().equals(entry.getValue()))
{
match = true;
break;
}
}
if(!match)
{
break;
}
}
if(match)
{
parents.add(o);
}
}
}
return filter(parents, request);
}
private Collection filter(Collection objects, HttpServletRequest request)
{
Map> filters = new HashMap>();
for(String param : (Collection) Collections.list(request.getParameterNames()))
{
if(!RESERVED_PARAMS.contains(param))
{
filters.put(param, Arrays.asList(request.getParameterValues(param)));
}
}
if(filters.isEmpty())
{
return objects;
}
Collection filteredObj = new ArrayList(objects);
Iterator iter = filteredObj.iterator();
while(iter.hasNext())
{
ConfiguredObject obj = iter.next();
for(Map.Entry> entry : filters.entrySet())
{
Object value = obj.getAttribute(entry.getKey());
if(!entry.getValue().contains(String.valueOf(value)))
{
iter.remove();
}
}
}
return filteredObj;
}
private Collection extends ConfiguredObject> getAncestors(Class extends ConfiguredObject> childType,
Class extends ConfiguredObject> ancestorType,
ConfiguredObject child)
{
Collection ancestors = new HashSet();
Collection> parentTypes = Model.getInstance().getParentTypes(childType);
for(Class extends ConfiguredObject> parentClazz : parentTypes)
{
if(parentClazz == ancestorType)
{
ConfiguredObject parent = child.getParent(parentClazz);
if(parent != null)
{
ancestors.add(parent);
}
}
else
{
ConfiguredObject parent = child.getParent(parentClazz);
if(parent != null)
{
ancestors.addAll(getAncestors(parentClazz, ancestorType, parent));
}
}
}
return ancestors;
}
@Override
protected void doGetWithSubjectAndActor(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_OK);
setCachingHeadersOnResponse(response);
Collection allObjects = getObjects(request);
// TODO - sort special params, everything else should act as a filter
int depth = getDepthParameterFromRequest(request);
List