/*
* Copyright (c) 2005-2010, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.wso2.carbon.registry.app;
import org.apache.abdera.Abdera;
import org.apache.abdera.factory.Factory;
import org.apache.abdera.i18n.iri.IRI;
import org.apache.abdera.model.*;
import org.apache.abdera.protocol.server.RequestContext;
import org.apache.abdera.protocol.server.ResponseContext;
import org.apache.abdera.protocol.server.Target;
import org.apache.abdera.protocol.server.TargetType;
import org.apache.abdera.protocol.server.context.AbstractResponseContext;
import org.apache.abdera.protocol.server.context.BaseResponseContext;
import org.apache.abdera.protocol.server.context.EmptyResponseContext;
import org.apache.abdera.protocol.server.context.ResponseContextException;
import org.apache.abdera.protocol.server.impl.AbstractEntityCollectionAdapter;
import org.apache.abdera.util.Constants;
import org.apache.abdera.util.EntityTag;
import org.apache.abdera.util.MimeTypeHelper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.registry.app.targets.ResourceTarget;
import org.wso2.carbon.registry.app.targets.ResponseTarget;
import org.wso2.carbon.registry.core.*;
import org.wso2.carbon.registry.core.Collection;
import org.wso2.carbon.registry.core.exceptions.RegistryException;
import org.wso2.carbon.registry.core.exceptions.ResourceNotFoundException;
import org.wso2.carbon.registry.core.jdbc.EmbeddedRegistryService;
import org.wso2.carbon.utils.multitenancy.MultitenantConstants;
import javax.activation.MimeType;
import javax.activation.MimeTypeParseException;
import javax.xml.namespace.QName;
import java.io.*;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.*;
/**
* This is the component that provides the business logic which runs on the Abdera instance. The
* Provider will use it's Workspace Manager to determine which Collection Adapter to dispatch a
* request to. Once an adapter is selected, the Provider will determine what kind of request is
* being made and will forward the request on to the appropriate Collection Adapter method.
* <p/>
* The Registry Adapter is a specialized Collection Adapter designed to expose registry logic within
* an APP world.
*/
@SuppressWarnings("deprecation")
// TODO: get rid of the global suppression on deprecation warnings, and fix the use of
// URLEncoder.encode, by providing the correct encoding.
public class RegistryAdapter
extends AbstractEntityCollectionAdapter<Resource> {
private final static Log log = LogFactory.getLog(RegistryAdapter.class);
private final static String sanitizePattern = "[^A-Za-z0-9\\.\\%!\\\\'()*+,=_\\s\\?]+";
private Factory factory = new Abdera().getFactory();
private int curResource = 1;
@Deprecated
@SuppressWarnings("unused")
public RegistryAdapter(RegistryResolver resolver,
EmbeddedRegistryService embeddedRegistryService)
throws RegistryException {
}
/**
* Default constructor
*/
public RegistryAdapter() {
}
/**
* Handle anything out of the ordinary Abdera-supported world.
* <p/>
* This method basically acts as a clearing house for all of the Registry-specific URLs that
* result in special processing, like ...;tags or ...;comments, etc. The resolver will have
* already parsed the URL and matched it with a particular custom TargetType, so in here we
* switch control based on the TargetType to a meta data processing routine.
*
* @param request the RequestContext containing all the relevant info
*
* @return a ResponseContext indicating the disposition of the request
*/
@SuppressWarnings({"ConstantConditions"})
public ResponseContext extensionRequest(RequestContext request) {
Target target = request.getTarget();
final TargetType type = target.getType();
if (!(target instanceof ResourceTarget)) {
if (type.equals(ResponseTarget.RESPONSE_TYPE)) {
return ((ResponseTarget) target).getResponse();
}
// Deal with non-resource URLs, like "/tags..."
if (type.equals(RegistryResolver.TAG_URL_TYPE)) {
return processTagURLRequest(request);
}
}
Resource resource = ((ResourceTarget) target).getResource();
String path = resource.getPath();
if (type.equals(RegistryResolver.TAGS_TYPE)) {
return processTagsRequest(request, path);
}
if (type.equals(RegistryResolver.LOGS_TYPE)) {
return processLogsRequest(request, path);
}
if (type.equals(RegistryResolver.RATINGS_TYPE)) {
return processRatingsRequest(request, path);
}
if (type.equals(RegistryResolver.VERSIONS_TYPE)) {
return processVersionsRequest(request, path);
}
if (type.equals(RegistryResolver.RENAME_TYPE)) {
return processRenameRequest(request, path);
}
if (type.equals(RegistryResolver.COPY_TYPE)) {
return processCopyRequest(request, path);
}
if (type.equals(RegistryResolver.MOVE_TYPE)) {
return processMoveRequest(request, path);
}
if (type.equals(RegistryResolver.DELETE_TYPE)) {
return processDeleteRequest(request, path);
}
if (type.equals(RegistryResolver.QUERY_TYPE)) {
return processQueryRequest(request, path);
}
if (type.equals(RegistryResolver.COLLECTION_CUSTOM_TYPE)) {
if (request.getMethod().equals("HEAD")) {
// Doing a HEAD on a collection
try {
return buildHeadEntryResponse(request, getId(resource),
resource.getLastModified());
} catch (ResponseContextException e) {
log.error(e);
return e.getResponseContext();
}
}
// Must be a PUT.
return putCollection(request, path);
}
if (type.equals(RegistryResolver.ASSOCIATIONS_TYPE)) {
String temp = resource.getPermanentPath();
if (temp == null) {
temp = resource.getPath();
}
return processAssociationRequest(request, temp);
}
if (type.equals(RegistryResolver.COMMENTS_TYPE)) {
return processCommentsRequest(request, path);
}
if (type.equals(RegistryResolver.RESTORE_TYPE)) {
try {
getSecureRegistry(request).restoreVersion(resource.getPermanentPath());
} catch (RegistryException e) {
return new StackTraceResponseContext(e);
}
return new EmptyResponseContext(200);
}
if (type.equals(RegistryResolver.ASPECT_TYPE)) {
return processAspectRequest(request, path);
}
if (type.equals(RegistryResolver.CHECKPOINT_TYPE)) {
return processCheckpointRequest(request, path);
}
// Deal with imports
if (type.equals(RegistryResolver.IMPORT_TYPE)) {
return processImportRequest(request, path);
}
// handle dump, restore request.
if (type.equals(RegistryResolver.DUMP_TYPE)) {
return processDumpRequest(request, path);
}
return null;
}
/**
* Handle PUT of a collection (a feed).
*
* @param request active RequestContext
* @param path the resource path
*
* @return a ResponseContext which could contain success or an error
*/
private ResponseContext putCollection(RequestContext request, String path) {
try {
final Registry secureRegistry = getSecureRegistry(request);
Collection resource = secureRegistry.newCollection();
Feed feed = (Feed) request.getDocument().getRoot();
// Just updating meta data
org.wso2.carbon.registry.app.Properties properties =
feed.getExtension(PropertyExtensionFactory.PROPERTIES);
RemoteRegistry.createPropertiesFromExtensionElement(properties, resource);
resource.setDescription(feed.getSubtitle());
if (feed.getSimpleExtension(new QName(APPConstants.NAMESPACE, "mediaType")) != null) {
resource.setMediaType(
feed.getSimpleExtension(new QName(APPConstants.NAMESPACE, "mediaType")));
}
secureRegistry.put(path, resource);
} catch (Exception e) {
return new StackTraceResponseContext(e);
}
EmptyResponseContext response = new EmptyResponseContext(200);
try {
response.setLocation(
URLDecoder.decode(getAtomURI(path, request), "UTF-8").replaceAll(" ", "+"));
} catch (UnsupportedEncodingException e) {
// no action
}
return response;
}
// Method to obtain the atom uri for the given path.
private String getAtomURI(String path, RequestContext context) {
return getAbsoluteBase(context) + APPConstants.ATOM + path;
}
// Method to obtain the base uri.
private String getAbsoluteBase(RequestContext context) {
String uri = context.getBaseUri().trailingSlash().toString();
uri = uri.substring(0, uri.length() - 1); // remove trailing slash
if (!uri.endsWith("registry")) {
uri += "/registry";
}
return uri;
}
// Method to obtain a new feed.
private Feed getNewFeed(String id) {
Feed feed = factory.newFeed();
feed.setId(id);
feed.setUpdated(new Date());
return feed;
}
/**
* Utility function to parse query string TODO: Isn't there a standard way to do this?
*
* @param query query string to parse
*
* @return a Map of name -> value for each parameter
*/
public static Map<String, String> parseQueryString(String query) {
Map<String, String> map = new HashMap<String, String>();
if (query == null) {
return map;
}
StringTokenizer st = new StringTokenizer(query, "?&=", true);
String previous = "";
while (st.hasMoreTokens()) {
String current = st.nextToken();
if ("?".equals(current) || "&".equals(current)) {
// nothing to do here
} else if ("=".equals(current)) {
try {
map.put(URLDecoder.decode(previous, "UTF-8"),
URLDecoder.decode(st.nextToken(), "UTF-8"));
} catch (UnsupportedEncodingException e) {
break;
}
} else {
previous = current;
}
}
return map;
}
// Method to obtain the absolute uri for the given path.
private String getAbsolutePath(RequestContext request, String path) {
return request.getBaseUri() + "atom" + path;
}
private ResponseContext processAspectRequest(RequestContext request, String path) {
String method = request.getMethod();
Registry registry;
try {
registry = getSecureRegistry(request);
} catch (RegistryException e) {
return new StackTraceResponseContext(e);
}
String discriminator =
((String[]) request.getAttribute(RequestContext.Scope.REQUEST, "splitPath"))[1];
if (discriminator.equals("aspects")) {
if (method.equals("GET")) {
// get aspects
} else if (method.equals("POST")) {
// Associate
try {
String aspect = readToString(request.getInputStream());
registry.associateAspect(path, aspect);
} catch (Exception e) {
return new StackTraceResponseContext(e);
}
return new EmptyResponseContext(200);
}
return null;
}
// There should be an aspect name - parse it out
assert (discriminator.charAt(7) == '(');
int right = discriminator.indexOf(')');
assert (right > -1);
String aspectName = discriminator.substring(7, right);
String action;
if (discriminator.length() > right + 1) {
// Got an action too?
assert (method.equals("POST"));
action = discriminator.substring(right + 1);
try {
registry.invokeAspect(path, aspectName, action);
} catch (RegistryException e) {
return new StackTraceResponseContext(e);
}
// TODO - do we have to read the request fully?
return new EmptyResponseContext(200);
}
assert (method.equals("GET"));
// Return list of available actions.
Feed feed = getNewFeed("tag:aspectActions"); // TODO - fix ID
String[] actions;
try {
actions = registry.getAspectActions(path, aspectName);
} catch (RegistryException e) {
return new StackTraceResponseContext(e);
}
for (String a : actions) {
Entry e = factory.newEntry();
e.setId("tag:aspectAction(" + a + ")");
e.setContent(a);
feed.addEntry(e);
}
return buildResponseContextFromFeed(feed);
}
private ResponseContext processCommentsRequest(RequestContext request, String path) {
final String method = request.getMethod();
if (method.equals("GET")) {
int colonIdx = request.getUri().toString().indexOf(':');
if (colonIdx > -1) {
return getEntry(request);
} else {
// Return comments feed
return getFeed(request);
}
} else {
try {
final Registry secureRegistry = getSecureRegistry(request);
if (method.equals("POST")) {
// Accept either Atom or plain text for comments
org.wso2.carbon.registry.core.Comment comment =
new org.wso2.carbon.registry.core.Comment();
final String contentType = request.getContentType().toString();
if (request.isAtom()) {
Entry entry = (Entry) request.getDocument().getRoot();
comment.setText(entry.getContent());
comment.setUser(entry.getAuthor().getName());
if (entry.getUpdated() != null) {
comment.setCreatedTime(entry.getUpdated());
}
} else if (contentType.equals("text/plain")) {
InputStream is = request.getInputStream();
String text = readToString(is);
comment.setText(text);
}
String commentPath = secureRegistry.addComment(path, comment);
EmptyResponseContext responseContext = new EmptyResponseContext(200);
try {
responseContext.setLocation(URLDecoder
.decode(getAtomURI(commentPath, request), "UTF-8").replaceAll(" ",
"+"));
} catch (UnsupportedEncodingException e) {
// no action
}
return responseContext;
} else if (method.equals("PUT")) {
Entry entry = (Entry) request.getDocument().getRoot();
String text = entry.getContent();
secureRegistry.editComment(path, text);
return new EmptyResponseContext(200);
} else if (method.equals("DELETE")) {
secureRegistry.delete(path);
return new EmptyResponseContext(200);
}
} catch (Exception e) {
return new StackTraceResponseContext(e);
}
}
return new EmptyResponseContext(405); // unsupported method
}
private ResponseContext processAssociationRequest(RequestContext request, String path) {
if (request.getMethod().equals("GET")) {
String type = null;
String uri = request.getUri().toString();
if (uri.indexOf(";version:") > 0) {
uri = uri.substring(uri.indexOf(";version:") + ";version:".length());
}
int idx = uri.lastIndexOf(":");
if (idx > -1) {
type = uri.substring(idx + 1, uri.length());
}
// Return associations feed
Association[] associations;
try {
if (type != null) {
associations = getSecureRegistry(request).getAssociations(path, type);
} else {
associations = getSecureRegistry(request).getAllAssociations(path);
}
} catch (RegistryException e) {
return new StackTraceResponseContext(e);
}
// Build feed
Feed feed = getNewFeed("tag:associationFeed");
for (Association association : associations) {
final String associationType = association.getAssociationType();
final String destinationPath = association.getDestinationPath();
Entry e = factory.newEntry();
e.setTitle("'" + associationType + "' association");
e.setId("tag:association"); // todo - ID should be unique
if (destinationPath.startsWith("http://")) {
e.addLink(URLEncoder.encode(destinationPath), Link.REL_ALTERNATE);
} else {
e.addLink(getAbsolutePath(request, destinationPath).replaceAll(" ", "+"));
}
e.setSummary(associationType);
e.setContent(destinationPath);
feed.addEntry(e);
}
return buildResponseContextFromFeed(feed);
}
if (request.getMethod().equals("POST")) {
// Adding an association, expecting XML that looks like
// <reg:association type="type">http://associationPath</reg:association>
try {
Element assocEl = request.getDocument().getRoot();
if (!APPConstants.QN_ASSOC.equals(assocEl.getQName())) {
return new EmptyResponseContext(400, "Bad association element");
}
String type = assocEl.getAttributeValue(APPConstants.ASSOC_TYPE);
String assocPath = assocEl.getText();
getSecureRegistry(request).addAssociation(path, assocPath, type);
return new EmptyResponseContext(200);
} catch (Exception e) {
return new StackTraceResponseContext(e);
}
}
if (request.getMethod().equals("DELETE")) {
String destinationPath = request.getHeader("Destination");
String type = request.getHeader("AssociationType");
try {
getSecureRegistry(request).removeAssociation(path, destinationPath, type);
return new EmptyResponseContext(200);
} catch (Exception e) {
return new StackTraceResponseContext(e);
}
}
return null;
}
private ResponseContext processTagURLRequest(RequestContext request) {
String uri = (String) request.getAttribute(RequestContext.Scope.REQUEST, "pathInfo");
if (uri.endsWith("/")) {
uri = uri.substring(0, uri.length() - 1);
}
if (uri.equals("/tags")) {
// TODO - implement this!
return new StringResponseContext("this is a list of tags with links", 200);
}
String tag = uri.substring(6);
Feed feed = getNewFeed("http://wso2.org/jdbcregistry/TagPaths");
feed.setTitle("Resource path for " + tag);
TaggedResourcePath[] paths;
try {
paths = getSecureRegistry(request).getResourcePathsWithTag(tag);
} catch (RegistryException e) {
return new StackTraceResponseContext(e);
}
for (TaggedResourcePath tagPath : paths) {
Entry entry = factory.newEntry();
String path = tagPath.getResourcePath();
entry.setTitle(path);
entry.addSimpleExtension(new QName(APPConstants.NAMESPACE, "taggings"),
"" + tagPath.getTagCount());
Map<String, String> tagCounts = tagPath.getTagCounts();
java.util.Properties properties = new java.util.Properties();
for (Map.Entry<String, String> e : tagCounts.entrySet()) {
properties.put(e.getKey(), Arrays.asList(e.getValue()));
}
/*Iterator<String> iCounts = tagCounts.keySet().iterator();
while (iCounts.hasNext()) {
String key = iCounts.next();
String count = tagCounts.get(key);
properties.put(key, Arrays.asList(count));
}*/
RemoteRegistry.addPropertyExtensionElement(properties,
factory,
entry,
PropertyExtensionFactory.TAGS,
PropertyExtensionFactory.TAG);
// entry.addSimpleExtension(new QName("tagCounts"), "" + tagPath.getTagCount())
// entry.addLink(baseUri + "atom" + path, "path");
// entry.addLink(baseUri + "atom" + path);
feed.addEntry(entry);
}
return buildResponseContextFromFeed(feed);
}
private ResponseContext processImportRequest(RequestContext request, String path) {
String slug = request.getSlug();
String suggestedPath = path + getGoodSlug(path, slug, request);
Resource resource = new ResourceImpl();
Document<Entry> doc;
try {
doc = request.getDocument();
} catch (IOException e) {
return new StackTraceResponseContext(e);
}
org.wso2.carbon.registry.app.Properties properties =
doc.getRoot().getExtension(PropertyExtensionFactory.PROPERTIES);
RemoteRegistry.createPropertiesFromExtensionElement(properties, resource);
resource.setMediaType(request.getContentType().toString());
String location;
try {
// InputStream is = request.getInputStream();
// String importURL = readToString(is);
// if (importURL.contains("=")) {
// importURL = importURL.substring(importURL.indexOf("=") + 1);
// }
// importURL = importURL.substring(0, importURL.lastIndexOf(";"));
// removes the "application/resource-import" string from incoming path
String importURL = request.getParameter("importURL");
if (importURL.endsWith(";application/resource-import")) {
importURL = importURL.substring(0, importURL.length() - ";application/resource-import".length());
}
location = getSecureRegistry(request).importResource(suggestedPath,
importURL,
resource);
} catch (Exception e) {
return new StringResponseContext(e, 500);
}
ResponseContext rc = new EmptyResponseContext(200);
try {
rc.setLocation(
URLDecoder.decode(getAtomURI(location, request), "UTF-8").replaceAll(" ", "+"));
} catch (UnsupportedEncodingException e) {
// no action
}
return rc;
}
private ResponseContext processRenameRequest(RequestContext request, String path) {
if (!request.getMethod().equals("POST")) {
ResponseContext rc = new EmptyResponseContext(405, "Method not allowed");
rc.setAllow("POST");
return rc;
}
try {
InputStream is = request.getInputStream();
String newPath = readToString(is);
getSecureRegistry(request).rename(path, newPath);
} catch (Exception e) {
return new StackTraceResponseContext(e);
}
return new StringResponseContext("Rename successful.", 200);
}
private ResponseContext processCopyRequest(RequestContext request, String path) {
if (!request.getMethod().equals("POST")) {
ResponseContext rc = new EmptyResponseContext(405, "Method not allowed");
rc.setAllow("POST");
return rc;
}
try {
InputStream is = request.getInputStream();
String newPath = readToString(is);
getSecureRegistry(request).copy(path, newPath);
} catch (Exception e) {
return new StackTraceResponseContext(e);
}
return new StringResponseContext("Copy successful.", 200);
}
private ResponseContext processMoveRequest(RequestContext request, String path) {
if (!request.getMethod().equals("POST")) {
ResponseContext rc = new EmptyResponseContext(405, "Method not allowed");
rc.setAllow("POST");
return rc;
}
try {
InputStream is = request.getInputStream();
String newPath = readToString(is);
getSecureRegistry(request).move(path, newPath);
} catch (Exception e) {
return new StackTraceResponseContext(e);
}
return new StringResponseContext("Move successful.", 200);
}
private ResponseContext processDeleteRequest(RequestContext request, String path) {
assert (request.getMethod().equals("DELETE"));
String tagName = null;
String commentId = null;
try {
Object temp = request.getAttribute(RequestContext.Scope.REQUEST, "tagName");
if (temp != null) {
tagName = URLDecoder.decode((String)temp, "UTF-8");
} else {
temp = request.getAttribute(RequestContext.Scope.REQUEST, "commentId");
if (temp != null) {
commentId = (String)temp;
}
}
} catch (Exception e) {
log.error("An exception occurred while processing removeTag request", e);
}
try {
if (tagName != null) {
getSecureRegistry(request).removeTag(path, tagName);
} else if (commentId != null) {
getSecureRegistry(request).removeComment(path + ";comments:" + commentId);
} else {
getSecureRegistry(request).delete(path);
}
} catch (RegistryException e) {
return new StackTraceResponseContext(e);
}
return new EmptyResponseContext(200);
}
private ResponseContext processRatingsRequest(RequestContext request, String path) {
if (request.getMethod().equals("GET")) {
// Return ratings feed.
Feed feed = factory.newFeed();
feed.setUpdated(new Date()); // TODO - updated at last rating
feed.setId("http://wso2.org/jdbcregistry:averageRating"); // TODO - make real ID
feed.setTitle("Average Rating for the resource " + path);
String nodeLink =
getAbsolutePath(request, Utils.encodeRegistryPath(path).replaceAll(" ", "+")) +
RegistryConstants.URL_SEPARATOR +
APPConstants.PARAMETER_RATINGS;
feed.addLink(nodeLink);
try {
Registry myRegistry = getSecureRegistry(request);
feed.addSimpleExtension(APPConstants.QN_AVERAGE_RATING,
"" + myRegistry.getAverageRating(path));
Resource r = myRegistry.get(path + RegistryConstants.URL_SEPARATOR +
"ratings");
Collection c;
if (r instanceof Collection) {
c = (Collection) r;
} else {
EmptyResponseContext res =
new EmptyResponseContext(400, "Empty Ratings result'");
myRegistry.get(path + RegistryConstants.URL_SEPARATOR + "ratings");
return res;
}
String[] ratings = (String[]) c.getContent();
if (ratings != null && ratings.length > 0) {
for (String rating : ratings) {
Entry e = factory.newEntry();
e.setId("tag:something"); // TODO - make real ID
e.setContent(rating);
e.addLink(rating, "path");
feed.addEntry(e);
}
}
} catch (RegistryException e) {
return new StackTraceResponseContext(e);
}
return buildResponseContextFromFeed(feed);
} else if (request.getMethod().equals("POST")) {
// We're trying to rate the resource.
try {
InputStream is = request.getInputStream();
String rateStr = readToString(is);
int rating = Integer.parseInt(rateStr);
getSecureRegistry(request).rateResource(path, rating);
return new StringResponseContext("Resource rated successfully", 200);
} catch (Exception e) {
return new StackTraceResponseContext(e);
}
}
return null;
}
private ResponseContext processQueryRequest(RequestContext request, String path) {
// TODO : Process PUT
String query = request.getUri().getQuery();
Map parameters;
if (query == null) {
parameters = new HashMap();
} else {
parameters = RemoteRegistry.decodeQueryString(query);
if (parameters == null) {
return new EmptyResponseContext(400,
"URI decoding failed on " + query + " at path " + path);
}
}
Feed feed;
try {
final Registry secureRegistry = getSecureRegistry(request);
Collection results = secureRegistry.executeQuery(path, parameters);
feed = getNewFeed("tag:id"); // TODO: generate correct ID
feed.setTitle(path);
String[] childPaths = results.getChildren();
for (String child : childPaths) {
Resource entryObj = secureRegistry.get(child);
Entry entry = factory.newEntry();
IRI feedIRI = new IRI(getFeedIriForEntry(entryObj, request));
addEntryDetails(request, entry, feedIRI, entryObj);
// entry.addLink(child, "queryResult");
feed.addEntry(entry);
}
} catch (Exception e) {
return new StackTraceResponseContext(e);
}
return buildResponseContextFromFeed(feed);
}
private ResponseContext processVersionsRequest(RequestContext request, String path) {
String[] versionPaths;
try {
Registry registry = getSecureRegistry(request);
versionPaths = registry.getVersions(path);
} catch (RegistryException e) {
return new StackTraceResponseContext(e);
}
Feed feed = getNewFeed("tag:" + path + ";versions");
for (String version : versionPaths) {
Entry e = factory.newEntry();
e.addLink(version, "versionLink");
feed.addEntry(e);
}
return buildResponseContextFromFeed(feed);
}
private ResponseContext processLogsRequest(RequestContext request, String path) {
Map<String, String> parameters = parseQueryString(request.getUri().getQuery());
String user = parameters.get("user");
Date fromDate = null;
Date toDate = null;
String recentParam = parameters.get("recentFirst");
DateFormat format = DateFormat.getDateInstance(DateFormat.SHORT);
String dateStr = parameters.get("from");
if (dateStr != null) {
try {
fromDate = format.parse(dateStr);
} catch (ParseException e) {
return new EmptyResponseContext(400, "Bad 'from' date format '" + dateStr + "'");
}
}
dateStr = parameters.get("to");
if (dateStr != null) {
try {
toDate = format.parse(dateStr);
} catch (ParseException e) {
return new EmptyResponseContext(400, "Bad 'to' date format '" + dateStr + "'");
}
}
boolean recentFirst = recentParam == null || recentParam.equals("true");
int action = -1;
LogEntry[] logs;
try {
final Registry reg = getSecureRegistry(request);
logs = reg.getLogs(path, action, user, fromDate, toDate, recentFirst);
} catch (RegistryException e) {
return new StackTraceResponseContext(e);
}
String uri = request.getUri().toString();
int colonIdx = uri.indexOf(':');
if (colonIdx > -1 && uri.length() > colonIdx + 1) {
int entryIdx;
try {
entryIdx = Integer.parseInt(uri.substring(colonIdx + 1));
} catch (NumberFormatException e) {
return new EmptyResponseContext(400, "Bad log entry id '" +
uri.substring(colonIdx + 1) + "'");
}
if (entryIdx < 0 || entryIdx > logs.length - 1) {
return new EmptyResponseContext(400, "Bad log entry id '" + entryIdx + "'");
}
LogEntry logentry = logs[logs.length - 1 - entryIdx];
Entry entry = factory.newEntry();
entry.setUpdated(new Date());
entry.setId("http://wso2.org/jdbcregistry,2007:logs:" + entryIdx);
entry.setTitle(logentry.getTitle());
entry.setEdited(logentry.getDate());
entry.setContentAsHtml(logentry.getText());
entry.addAuthor(logentry.getUserName());
entry.addSimpleExtension(new QName(APPConstants.NAMESPACE, "action"),
"" + logentry.getAction());
entry.addSimpleExtension(new QName(APPConstants.NAMESPACE, "path"),
logentry.getResourcePath());
try {
return buildGetEntryResponse(request, entry);
} catch (ResponseContextException e) {
return createErrorResponse(e);
}
}
Feed feed = factory.newFeed();
feed.setId("http://wso2.org/jdbcregistry,2007:logs");
feed.setTitle("Logs for the resource " + path);
feed.addLink("", Link.REL_SELF);
feed.setUpdated(new Date());
int count = logs.length - 1;
for (LogEntry logentry : logs) {
Entry entry = factory.newEntry();
entry.setTitle(logentry.getTitle());
entry.addLink((request.getUri() + ":" +
count).replaceAll(" ", "+"));
count--;
entry.setEdited(logentry.getDate());
entry.setContentAsHtml(logentry.getText());
entry.addAuthor(logentry.getUserName());
entry.addSimpleExtension(new QName(APPConstants.NAMESPACE, "action"),
"" + logentry.getAction());
entry.addSimpleExtension(new QName(APPConstants.NAMESPACE, "path"),
logentry.getResourcePath());
feed.addEntry(entry);
}
return buildResponseContextFromFeed(feed);
}
private ResponseContext processCheckpointRequest(RequestContext request, String path) {
try {
Registry registry = getSecureRegistry(request);
registry.createVersion(path);
} catch (RegistryException e) {
return new StackTraceResponseContext(e);
}
return new StringResponseContext("Version successfully created", 200);
}
private ResponseContext buildResponseContextFromFeed(Feed feed) {
Document<Feed> docFeed = feed.getDocument();
ResponseContext rc = new BaseResponseContext<Document<Feed>>(docFeed);
rc.setEntityTag(calculateEntityTag(docFeed.getRoot()));
Date updated = feed.getUpdated();
if (updated != null) {
rc.setLastModified(updated);
}
return rc;
}
private ResponseContext processTagsRequest(RequestContext request, String path) {
if (request.getMethod().equals("GET")) {
// Return the tags.
// TODO - resource.getTags()?
Tag[] tags;
try {
final Registry reg = getSecureRegistry(request);
tags = reg.getTags(path);
} catch (RegistryException e) {
return new StackTraceResponseContext(e);
}
Feed feed = factory.newFeed();
feed.setId("http://wso2.org/jdbcregistry:tags" +
Utils.encodeRegistryPath(path).replaceAll(" ", "+"));
feed.setTitle("Tags for " + path);
// String nodeLink = baseUri + "atom" + path +
// RegistryConstants.URL_SEPARATOR +
// PARAMETER_TAGS;
// feed.addLink(nodeLink);
feed.setUpdated(new Date());
for (Tag tag : tags) {
Entry entry = factory.newEntry();
entry.setTitle(tag.getTagName());
entry.setContent(tag.getTagName());
entry.addSimpleExtension(new QName(APPConstants.NAMESPACE, "taggings"),
"" + tag.getTagCount());
feed.addEntry(entry);
}
return buildResponseContextFromFeed(feed);
}
if (request.getMethod().equals("POST")) {
// POST adds a tag
if (request.isAtom()) {
String tag;
try {
Entry e = (Entry) request.getDocument().getRoot();
tag = e.getContent();
final Registry registry = getSecureRegistry(request);
registry.applyTag(path, tag);
} catch (Exception e) {
return new StackTraceResponseContext(e);
}
final EmptyResponseContext response = new EmptyResponseContext(200, "Tag applied");
try {
response.setLocation(URLDecoder.decode(getAbsolutePath(request, path), "UTF-8")
.replaceAll(" ", "+") +
RegistryConstants.URL_SEPARATOR + "tags:" + tag);
} catch (UnsupportedEncodingException e) {
// no action
}
return response;
}
String firstTag = null;
try {
InputStream is = request.getInputStream();
String tagText = readToString(is);
String[] tags = tagText.split(" ");
for (String tag : tags) {
if (firstTag == null) {
firstTag = tag;
}
try {
final Registry registry = getSecureRegistry(request);
registry.applyTag(path, tag);
} catch (RegistryException e) {
return new StackTraceResponseContext(e);
}
}
} catch (IOException e) {
return new StackTraceResponseContext(e);
}
final EmptyResponseContext response = new EmptyResponseContext(200, "Tag applied");
try {
response.setLocation(URLDecoder.decode(getAbsolutePath(request, path), "UTF-8")
.replaceAll(" ", "+") +
RegistryConstants.URL_SEPARATOR + "tags:" + firstTag);
} catch (UnsupportedEncodingException e) {
// no action
}
return response;
}
return null;
}
@SuppressWarnings("ThrowableInstanceNeverThrown")
private ResponseContext processDumpRequest(RequestContext request, String path) {
if (request.getMethod().equals("POST")) {
// We're trying to restore the dump resource.
try {
Reader reader = request.getReader();
getSecureRegistry(request).restore(path, reader);
return new StringResponseContext("Resource restored successfully", 200);
} catch (Exception e) {
return new StackTraceResponseContext(e);
}
} else if (request.getMethod().equals("GET")) {
// get the dump
try {
return new OMElementResponseContext(getSecureRegistry(request), path);
} catch (Exception e) {
return new StackTraceResponseContext(e);
}
} else {
String msg = "Invalid http method with the restore " + path + ". " +
"Expected post to restore and get to dump.";
log.error(msg);
// We need an exception object to create a stack trace response context.
return new StackTraceResponseContext(new RegistryException(msg));
}
}
/**
* Method to build a get entry response.
*
* @param request the request context.
* @param entry the entry
*
* @return the response context.
*/
protected ResponseContext buildGetEntryResponse(RequestContext request, Entry entry)
throws ResponseContextException {
Feed feed = createFeedBase(request);
entry.setSource(feed.getAsSource());
Document<Entry> entry_doc = entry.getDocument();
AbstractResponseContext rc = new BaseResponseContext<Document<Entry>>(entry_doc);
rc.setEntityTag(calculateEntityTag(entry));
Date updated = entry.getUpdated();
if (updated != null) {
rc.setLastModified(updated);
}
return rc;
}
/**
* Method to build a get feed response.
*
* @param feed the feed.
*
* @return the response context.
*/
protected ResponseContext buildGetFeedResponse(Feed feed) {
Document<Feed> document = feed.getDocument();
AbstractResponseContext rc = new BaseResponseContext<Document<Feed>>(document);
rc.setEntityTag(calculateEntityTag(document.getRoot()));
Date updated = feed.getUpdated();
if (updated != null) {
rc.setLastModified(updated);
}
return rc;
}
// Method to read an input stream to string
private String readToString(InputStream is) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(is));
StringBuffer buffer = new StringBuffer();
String line;
while ((line = in.readLine()) != null) {
buffer.append(line);
}
return buffer.toString();
}
// Method to calculate Entity Tag
private EntityTag calculateEntityTag(Base base) {
String id = null;
String modified = null;
if (base instanceof Entry) {
id = ((Entry) base).getId().toString();
if (((Entry) base).getUpdatedElement() != null) {
modified = ((Entry) base).getUpdatedElement().getText();
}
} else if (base instanceof Feed) {
id = ((Feed) base).getId().toString();
modified = ((Feed) base).getUpdatedElement().getText();
}
return EntityTag.generate(id, modified);
}
/**
* Method to post an entry.
*
* @param request the request context.
*
* @return the response context.
*/
public ResponseContext postEntry(RequestContext request) {
Document<Element> document;
try {
document = request.getDocument(request.getAbdera().getParser());
} catch (IOException e) {
return new StackTraceResponseContext(e);
}
if (document.getRoot().getQName().equals(Constants.FEED)) {
// Posting a <feed>, so this is probably a collection creation.
return postFeed(request);
}
return super.postEntry(request);
}
/**
* Method to post a feed.
*
* @param request the request context.
*
* @return the response context.
*/
public ResponseContext postFeed(RequestContext request) {
Document<Feed> doc;
try {
doc = request.getDocument();
} catch (IOException e) {
return new StackTraceResponseContext(e);
}
Feed feed = doc.getRoot();
String slug = request.getSlug();
if (slug == null) {
slug = feed.getTitle();
}
// Following code replaces spaces with "_". Commenting out Sanitizer.sanitize and doing the same thing other
// replacing spaces with "_".
// slug = Sanitizer.sanitize(slug, "-", sanitizePattern);
slug = slug.replaceAll(sanitizePattern, "-");
String parentPath = ((ResourceTarget) request.getTarget()).getResource().getPath();
if (!parentPath.endsWith(RegistryConstants.PATH_SEPARATOR)) {
parentPath += RegistryConstants.PATH_SEPARATOR;
}
String path = parentPath + slug;
String real;
try {
final Registry registry = getSecureRegistry(request);
Collection resource = registry.newCollection();
org.wso2.carbon.registry.app.Properties properties =
feed.getExtension(PropertyExtensionFactory.PROPERTIES);
RemoteRegistry.createPropertiesFromExtensionElement(properties, resource);
resource.setDescription(feed.getSubtitle());
if (feed.getSimpleExtension(new QName(APPConstants.NAMESPACE, "mediaType")) != null) {
resource.setMediaType(
feed.getSimpleExtension(new QName(APPConstants.NAMESPACE, "mediaType")));
}
real = registry.put(path, resource);
} catch (RegistryException e) {
return new StackTraceResponseContext(e);
}
StringResponseContext responseContext =
new StringResponseContext("Feed created at " + real, 201);
Map<String, String> map = new HashMap<String, String>();
map.put("collection", real.substring(1));
try {
responseContext.setLocation(URLDecoder.decode(request.absoluteUrlFor(
TargetType.TYPE_COLLECTION, map), "utf-8").replaceAll(" ", "+"));
} catch (UnsupportedEncodingException e) {
log.error("The encoding is not supported.", e);
}
return responseContext;
}
/**
* Method to post an entry to the collection.
*
* @param title the title of the entry.
* @param updated the updated time.
* @param authors the list of authors.
* @param summary the summary text.
* @param content the resource content.
* @param request the request context.
*
* @throws ResponseContextException if the operation failed.
*/
public Resource postEntry(String title,
IRI id,
String summary,
Date updated,
List<Person> authors,
Content content,
RequestContext request) throws ResponseContextException {
Resource resource = ((ResourceTarget) request.getTarget()).getResource();
String path = resource.getPath();
final Registry registry;
try {
registry = getSecureRegistry(request);
} catch (RegistryException e) {
throw new ResponseContextException(new StackTraceResponseContext(e));
}
final String[] splitPath = (String[]) request.getAttribute(RequestContext.Scope.REQUEST,
"splitPath");
final String text = content.getText();
if (splitPath != null) {
if ("comments".equals(splitPath[1])) {
// Comment post
org.wso2.carbon.registry.core.Comment comment =
new org.wso2.carbon.registry.core.Comment(text);
try {
registry.editComment(path, text);
String commentPath = registry.addComment(path, comment);
comment.setPath(commentPath);
} catch (RegistryException e) {
throw new ResponseContextException(new StackTraceResponseContext(e));
}
return comment;
}
}
String name = request.getSlug();
if (name == null) {
if (title != null) {
// Following code replaces spaces with "_". Commenting out Sanitizer.sanitize and
// doing the same thing other
// replacing spaces with "_".
// slug = Sanitizer.sanitize(slug, "-", sanitizePattern);
name = title.replaceAll(sanitizePattern, "-");
} else {
name = generateResourceName();
}
} else {
// name = Sanitizer.sanitize(name, "-", sanitizePattern);
}
if (!path.endsWith("/")) {
path += "/";
}
if (APPConstants.IMPORT_MEDIA_TYPE.equals(request.getContentType().toString())) {
// This is an import.
String importURL = request.getParameter("importURL");
String suggestedPath = request.getSlug();
String location;
try {
final Registry secureRegistry = getSecureRegistry(request);
location = secureRegistry.importResource(suggestedPath,
importURL,
new ResourceImpl());
return secureRegistry.get(location);
} catch (RegistryException e) {
throw new ResponseContextException(new StackTraceResponseContext(e));
}
}
Entry entry;
try {
entry = (Entry) request.getDocument().getRoot();
} catch (IOException e) {
throw new ResponseContextException(new StackTraceResponseContext(e));
}
Resource ret;
try {
ret = registry.newResource();
fillResourceFromEntry(entry, ret);
registry.put(path + name, ret);
} catch (Exception e) {
throw new ResponseContextException(new StackTraceResponseContext(e));
}
((ResourceImpl) ret).setPath(path + name);
return ret;
}
// Method to fill a resource from an entry.
private void fillResourceFromEntry(Entry entry, Resource ret) throws RegistryException {
org.wso2.carbon.registry.app.Properties properties =
entry.getExtension(PropertyExtensionFactory.PROPERTIES);
RemoteRegistry.createPropertiesFromExtensionElement(properties, ret);
String mediaType = entry.getSimpleExtension(new QName(APPConstants.NAMESPACE, "mediaType"));
if (mediaType != null) {
ret.setMediaType(mediaType);
}
Content content = entry.getContentElement();
if (content == null || content.getText() == null || content.getText().equals("")) {
// creates an null input stream.
ret.setContent(null);
} else if (content.getContentType() == Content.Type.TEXT) {
ret.setContent(content.getText());
if (mediaType == null) {
mediaType = "text/plain";
}
ret.setMediaType(mediaType);
} else if (content.getContentType() == Content.Type.MEDIA) {
try {
ret.setContentStream(content.getDataHandler().getInputStream());
} catch (IOException e) {
log.error(e);
return;
}
// if (mediaType == null) ret.setMediaType(content.getMimeType().toString());
}
if (entry.getSummary() != null) {
ret.setDescription(entry.getSummary());
}
}
/**
* Method to delete an entry from the collection.
*
* @param resourceName the resource name.
* @param request the request context.
*
* @throws ResponseContextException if the operation failed.
*/
public void deleteEntry(String resourceName, RequestContext request)
throws ResponseContextException {
}
/**
* Method to determine whether the given resource is a media entry.
*
* @param entry the resource.
*
* @return whether the given resource is a media entry.
* @throws ResponseContextException if the operation failed.
*/
public boolean isMediaEntry(Resource entry) throws ResponseContextException {
if (entry instanceof Collection) {
return false;
}
// If this isn't atom, it's a media entry
Object content;
try {
content = entry.getContent();
} catch (RegistryException e) {
throw new ResponseContextException(new StackTraceResponseContext(e));
}
return (!MimeTypeHelper.isAtom(entry.getMediaType()) && !(content instanceof Number) &&
!(content instanceof String));
}
/**
* Method to obtain the resource content.
*
* @param entry the resource.
* @param request the request context.
*
* @return the resource content object.
* @throws ResponseContextException
*/
public Object getContent(Resource entry, RequestContext request)
throws ResponseContextException {
// No content for Collections
if (entry instanceof Collection) {
return null;
}
Object c;
try {
c = entry.getContent();
} catch (RegistryException e) {
return null;
}
return c.toString();
}
/**
* Method to obtain the entry IRI link.
*
* @param entryObj the entry object.
* @param feedIri the feed IRI
* @param requestContext the request context.
*
* @return the entry IRI link.
* @throws ResponseContextException if the operation failed.
*/
protected String getLink(Resource entryObj, IRI feedIri, RequestContext requestContext)
throws ResponseContextException {
String path = entryObj.getPath();
final int idx = path.indexOf("ratings:");
String link;
if (entryObj instanceof org.wso2.carbon.registry.core.Comment) {
String name = path.substring(path.indexOf(':'));
link = feedIri.toString() + name;
} else if (idx > -1) {
link = feedIri.toString();
} else {
link = super.getLink(entryObj, feedIri, requestContext);
}
// if the request comes with the tenant domain as a parameter we insert the tenant domain
// for all the referred link
String tenantDomain = (String) requestContext.getAttribute(RequestContext.Scope.REQUEST,
MultitenantConstants.TENANT_DOMAIN);
if (tenantDomain != null && !tenantDomain.equals("")) {
int atomPos = link.indexOf("/registry/atom");
if (atomPos != -1) {
link = link.substring(0, atomPos) + "/" + MultitenantConstants.TENANT_AWARE_URL_PREFIX +
"/" + tenantDomain + "/registry/atom" +
link.substring(atomPos + "/registry/atom".length());
}
int resourcePos = link.indexOf("/registry/resource");
if (resourcePos != -1) {
link = link.substring(0, resourcePos) + "/" +
MultitenantConstants.TENANT_AWARE_URL_PREFIX +
"/" + tenantDomain + "/registry/resource" +
link.substring(resourcePos + "/registry/resource".length());
}
}
return link;
}
/**
* Method to add entry details.
*
* @param entry the entry.
* @param feedIri the IRI of the feed.
* @param entryObj the resource.
* @param request the request context.
*
* @return the entry IRI link.
* @throws ResponseContextException if the operation failed.
*/
protected String addEntryDetails(RequestContext request,
Entry entry,
IRI feedIri,
Resource entryObj) throws ResponseContextException {
// final Registry registry;
// try {
// registry = getSecureRegistry(request);
// } catch (RegistryException ex) {
// throw new ResponseContextException(new StackTraceResponseContext(ex));
// }
if (entryObj == null) {
return null;
}
final String link = getLink(entryObj, feedIri, request);
// We need an alternate link for the collection here
//if (!(entryObj instanceof org.wso2.carbon.registry.core.Comment)) {
entry.addLink(link, Link.REL_ALTERNATE);
//}
// if (entryObj instanceof Collection) {
// }
// String foo = request.getBaseUri().toString();
// foo += entryObj.getPath();
// e.addLink(foo, "alternate");
if (entryObj instanceof org.wso2.carbon.registry.core.Comment) {
entry.addLink(link, Link.REL_SELF);
entry.addLink(URLEncoder.encode(
((org.wso2.carbon.registry.core.Comment) entryObj).getResourcePath()),
"resourcePath");
String commentText = ((org.wso2.carbon.registry.core.Comment) entryObj).getText();
entry.setContent(commentText);
entry.setSummary(commentText);
}
entry.addLink(URLEncoder.encode(entryObj.getPath()), "path");
long snapshotID = ((ResourceImpl) entryObj).getMatchingSnapshotID();
if (snapshotID > -1) {
entry.addSimpleExtension(APPConstants.QN_SNAPSHOT_ID, Long.toString(snapshotID));
}
entry.addSimpleExtension(APPConstants.QN_LAST_UPDATER, entryObj.getLastUpdaterUserName());
if (entryObj.getCreatedTime() != null) {
entry.addSimpleExtension(new QName(APPConstants.NAMESPACE, "createdTime"),
String.valueOf(entryObj.getCreatedTime().getTime()));
}
final String mediaType = entryObj.getMediaType();
if (mediaType != null && mediaType.length() > 0) {
entry.addSimpleExtension(APPConstants.QN_MEDIA_TYPE, mediaType);
}
// String path = entryObj.getPath();
// try {
// Tag [] tags = registry.getTags(path);
// if (tags.length > 0) {
// Element ext = factory.newElement(new QName(RegistryConstants.REGISTRY_NAMESPACE,
// "tags"));
// for (Tag tag : tags) {
// Element tagEl =
// factory.newElement(new QName(RegistryConstants.REGISTRY_NAMESPACE,
// "tag"),
// ext);
// tagEl.setText(tag.getTagName());
// }
// e.addExtension(ext);
// }
// } catch (RegistryException e1) {
// log.error(e1);
// }
RemoteRegistry.addPropertyExtensionElement(entryObj.getProperties(),
factory,
entry,
PropertyExtensionFactory.PROPERTIES,
PropertyExtensionFactory.PROPERTY);
return super.addEntryDetails(request, entry, feedIri, entryObj);
}
/**
* Method to add feed details.
*
* @param feed the feed.
* @param request the request context.
*
* @throws ResponseContextException if the operation failed.
*/
protected void addFeedDetails(Feed feed, RequestContext request)
throws ResponseContextException {
super.addFeedDetails(feed, request);
final Resource resource = ((ResourceTarget) request.getTarget()).getResource();
RemoteRegistry.addPropertyExtensionElement(resource.getProperties(),
factory,
feed,
PropertyExtensionFactory.PROPERTIES,
PropertyExtensionFactory.PROPERTY);
if (request.getTarget().getType() == RegistryResolver.COMMENTS_TYPE) {
feed.addSimpleExtension(APPConstants.QN_COMMENTS, "true");
}
feed.addSimpleExtension(APPConstants.QN_LAST_UPDATER, resource.getLastUpdaterUserName());
long snapshotID = ((ResourceImpl) resource).getMatchingSnapshotID();
if (snapshotID > -1) {
feed.addSimpleExtension(APPConstants.QN_SNAPSHOT_ID, Long.toString(snapshotID));
}
if (resource instanceof Collection) {
try {
feed.addSimpleExtension(APPConstants.QN_CHILD_COUNT,
"" + ((Collection) resource).getChildCount());
} catch (RegistryException e) {
throw new ResponseContextException(new StackTraceResponseContext(e));
}
}
if (resource.getCreatedTime() != null) {
feed.addSimpleExtension(new QName(APPConstants.NAMESPACE, "createdTime"),
String.valueOf(resource.getCreatedTime().getTime()));
}
feed.addLink(URLEncoder.encode(resource.getPath()), "path");
feed.setSubtitle(resource.getDescription());
}
/**
* Method to get an iterator of entries.
*
* @param request the request context.
*
* @return an iterator of resources.
* @throws ResponseContextException if the operation failed.
*/
public Iterable<Resource> getEntries(final RequestContext request)
throws ResponseContextException {
Resource resource = ((ResourceTarget) request.getTarget()).getResource();
final String[] splitPath = (String[]) request.getAttribute(RequestContext.Scope.REQUEST,
"splitPath");
if (splitPath != null) {
if ("comments".equals(splitPath[1])) {
// Looking for comments, not the resource itself
try {
resource = getSecureRegistry(request).get(resource.getPath() +
RegistryConstants.URL_SEPARATOR +
"comments");
} catch (RegistryException e) {
throw new ResponseContextException(new StackTraceResponseContext(e));
}
}
}
if (resource instanceof Collection) {
final Resource r = resource;
return new Iterable<Resource>() {
public Iterator<Resource> iterator() {
try {
return new ResourceIterator((Object[]) r.getContent(),
getSecureRegistry(request));
} catch (RegistryException e) {
return null;
}
}
};
}
return null;
}
/**
* An implementation of an iterator, which is capable of iterating resources.
*/
private static class ResourceIterator implements Iterator<Resource> {
Object[] paths;
int i = 0;
Registry registry;
/**
* Constructor accepting an array of resource paths and a registry instance.
*
* @param paths array of resource paths.
* @param registry the registry instance.
*/
public ResourceIterator(Object[] paths, Registry registry) {
this.paths = paths;
this.registry = registry;
}
public boolean hasNext() {
return i < paths.length;
}
public Resource next() {
Object resourceOrString = paths[i++];
if (resourceOrString instanceof Resource) {
return (Resource) resourceOrString;
}
try {
return registry.get((String) resourceOrString);
} catch (RegistryException e) {
return null;
}
}
public void remove() {
}
}
/**
* Method to obtain the resource from the request.
*
* @param resourceName the resource name.
* @param request the request.
*
* @return the resource.
* @throws ResponseContextException if the operation failed.
*/
public Resource getEntry(String resourceName, RequestContext request)
throws ResponseContextException {
return ((ResourceTarget) request.getTarget()).getResource();
}
/**
* Method to obtain the unique identifier of a resource.
*
* @param entry the resource.
*
* @return the unique identifier.
* @throws ResponseContextException if the operation failed.
*/
public String getId(Resource entry) throws ResponseContextException {
return "urn:uuid:" + Utils.getUUID(entry.getId());
}
/**
* Method to obtain the name of a resource.
*
* @param entry the resource.
*
* @return the name.
* @throws ResponseContextException if the operation failed.
*/
public String getName(Resource entry) throws ResponseContextException {
String path = entry.getPath();
//path = IRI.normalizeString(path);
int idx = path.lastIndexOf('/');
path = path.substring(idx + 1, path.length());
return URLEncoder.encode(path);
}
/**
* Method to obtain the title of a resource.
*
* @param entry the resource.
*
* @return the title.
* @throws ResponseContextException if the operation failed.
*/
public String getTitle(Resource entry) throws ResponseContextException {
if (entry instanceof org.wso2.carbon.registry.core.Comment) {
return "Comment by " + entry.getAuthorUserName();
}
return entry.getPath();
}
/**
* Method to obtain the updated time of a resource.
*
* @param entry the resource.
*
* @return the updated time.
* @throws ResponseContextException if the operation failed.
*/
public Date getUpdated(Resource entry) throws ResponseContextException {
return entry.getLastModified();
}
/**
* Method to add an entry to the collection.
*
* @param request the request context.
*
* @return the response context.
*/
public ResponseContext putEntry(RequestContext request) {
String path = ((ResourceTarget) request.getTarget()).getResource().getPath();
Resource ret;
try {
Entry entry = (Entry) request.getDocument().getRoot();
Registry registry = getSecureRegistry(request);
ret = registry.newResource();
fillResourceFromEntry(entry, ret);
registry.put(path, ret);
} catch (Exception e) {
return new StackTraceResponseContext(e);
}
return new EmptyResponseContext(200);
}
/**
* Method to add an entry to the collection.
*
* @param entry the resource to add.
* @param title the title of the entry.
* @param updated the updated time.
* @param authors the list of authors.
* @param summary the summary text.
* @param content the resource content.
* @param request the request context.
*
* @throws ResponseContextException if the operation failed.
*/
public void putEntry(Resource entry,
String title,
Date updated,
List<Person> authors,
String summary,
Content content,
RequestContext request) throws ResponseContextException {
}
/**
* Method to obtain the primary author for an entry.
*
* @param request the request context.
*
* @return the primary author.
*/
public String getAuthor(RequestContext request) throws ResponseContextException {
return ((ResourceTarget) request.getTarget()).getResource().getAuthorUserName();
}
/**
* Method to obtain the list of authors for an entry.
*
* @param entry the resource entry.
* @param request the request context.
*
* @return the list of authors.
* @throws ResponseContextException if the operation failed.
*/
public List<Person> getAuthors(Resource entry, RequestContext request)
throws ResponseContextException {
Person author = request.getAbdera().getFactory().newAuthor();
author.setName(entry.getAuthorUserName());
return Arrays.asList(author);
}
/**
* Method to obtain the identifier for an entry.
*
* @param request the request context.
*
* @return the identifier.
*/
public String getId(RequestContext request) {
try {
return getId(((ResourceTarget) request.getTarget()).getResource());
} catch (ResponseContextException e) {
return null;
}
}
/**
* Method to obtain the title for an entry.
*
* @param request the request context.
*
* @return the title.
*/
public String getTitle(RequestContext request) {
Resource resource = ((ResourceTarget) request.getTarget()).getResource();
if (request.getTarget().getType().equals(RegistryResolver.COMMENTS_TYPE)) {
return "Comments for '" + resource.getPath() + "'";
}
return resource.getPath();
}
/**
* Method to obtain the summary for an entry.
*
* @param entry the resource entry.
* @param request the request context.
*
* @return the summary text.
* @throws ResponseContextException if the operation failed.
*/
public Text getSummary(Resource entry, RequestContext request) throws ResponseContextException {
Text text = factory.newSummary();
text.setValue(entry.getDescription());
return text;
}
/**
* Posts a new media entry.
*
* @param mimeType the MIME type of the content.
* @param slug the slug as a String.
* @param inputStream the content stream.
* @param request the request context.
*
* @return the generated media object.
* @throws ResponseContextException if the operation failed.
*/
public Resource postMedia(MimeType mimeType,
String slug,
InputStream inputStream,
RequestContext request) throws ResponseContextException {
final Registry registry;
try {
registry = getSecureRegistry(request);
} catch (RegistryException e) {
throw new ResponseContextException(new StackTraceResponseContext(e));
}
String path = ((ResourceTarget) request.getTarget()).getResource().getPath();
final String[] splitPath = (String[]) request.getAttribute(RequestContext.Scope.REQUEST,
"splitPath");
if (splitPath != null) {
if ("comments".equals(splitPath[1])) {
if (!mimeType.toString().equals("text/plain")) {
throw new ResponseContextException(
"Can only post Atom or text/plain to comments!", 400);
}
// Comment post
org.wso2.carbon.registry.core.Comment comment;
try {
comment = new org.wso2.carbon.registry.core.Comment(readToString(inputStream));
} catch (IOException e) {
throw new ResponseContextException(new StackTraceResponseContext(e));
}
try {
String commentPath = registry.addComment(path, comment);
comment.setPath(commentPath);
comment.setParentPath(path + RegistryConstants.URL_SEPARATOR + "comments");
} catch (RegistryException e) {
throw new ResponseContextException(new StackTraceResponseContext(e));
}
return comment;
}
}
if (!path.endsWith("/")) {
path += "/";
}
slug = getGoodSlug(path, slug, request);
path = path + slug;
boolean isCollection = "app/collection".equals(mimeType.toString());
Resource ret;
try {
ret = isCollection ? registry.newCollection() : registry.newResource();
} catch (RegistryException e) {
throw new ResponseContextException(new StackTraceResponseContext(e));
}
ret.setMediaType(mimeType.toString());
try {
if (!isCollection) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
try {
while (inputStream.available() > 0) {
int amount = inputStream.read(buffer, 0, 1024);
bos.write(buffer, 0, amount);
}
} catch (IOException e) {
// nothing here
}
String content = new String(bos.toByteArray());
ret.setContent(content);
}
registry.put(path, ret);
} catch (RegistryException e) {
throw new ResponseContextException(new StackTraceResponseContext(e));
}
return ret;
}
// Method to generate slug.
private String getGoodSlug(String path, String slug, RequestContext request) {
if (slug == null) {
slug = "resource";
}
// slug = Sanitizer.sanitize(slug, "", sanitizePattern);
if (slug.startsWith("/")) {
slug = slug.substring(1);
}
try {
Registry myRegistry = getSecureRegistry(request);
Resource resource = myRegistry.get(path + slug);
while (resource != null) {
int i = 1;
final int len = slug.length();
char c = slug.charAt(len - i);
while (i < len && c >= '0' && c <= '9') {
i++;
c = slug.charAt(len - i);
}
int j;
if (i == 1) {
j = 1;
} else {
String prefix = slug.substring(0, len - i + 1);
j = Integer.parseInt(slug.substring(len - i + 1)) + 1;
slug = prefix;
}
slug = slug + j;
resource = myRegistry.get(path + slug);
}
} catch (ResourceNotFoundException ignore) {
// We are expecting an exception here, and it is not an error this time.
log.debug("The resource was not found at path: " + path + slug);
} catch (RegistryException e) {
log.error("The operation failed", e);
return null;
}
return slug;
}
/**
* Method to obtain the content type of an entry.
*
* @param entry the entry.
*
* @return the content type.
*/
public String getContentType(Resource entry) {
return entry.getMediaType();
}
/**
* Method to obtain the media name.
*
* @param entry the resource (media entry).
*
* @return the media name.
* @throws ResponseContextException if the operation failed.
*/
public String getMediaName(Resource entry) throws ResponseContextException {
return entry.getPath().substring(1);
}
/**
* Method to add media content.
*
* @param feedIri the feed IRI.
* @param entry the entry.
* @param entryObj the resource object.
* @param request the request context.
*
* @return the added media IRI.
* @throws ResponseContextException
*/
protected String addMediaContent(IRI feedIri,
Entry entry,
Resource entryObj,
RequestContext request) throws ResponseContextException {
String fullUrl;
if (entry.getAlternateLink() != null && entry.getAlternateLink().getHref() != null) {
fullUrl = entry.getAlternateLink().getHref().toString();
if (fullUrl == null || fullUrl.length() == 0 ||
fullUrl.indexOf(APPConstants.ATOM) <= 0) {
fullUrl = feedIri.toString();
}
} else {
fullUrl = feedIri.toString();
}
String absoluteBase = fullUrl.substring(0, fullUrl.indexOf(APPConstants.ATOM));
IRI mediaIri = new IRI(absoluteBase + APPConstants.RESOURCE + "/"
+ URLEncoder.encode(getMediaName(entryObj)));
String mediaLink = mediaIri.toString();
String mime = getContentType(entryObj);
if (mime == null) {
mime = "application/octet-stream";
}
try {
new MimeType().match(mime);
} catch (MimeTypeParseException e) {
mime = "application/octet-stream";
}
entry.setContent(mediaIri, mime);
entry.addLink(mediaLink, Link.REL_EDIT_MEDIA);
return mediaLink;
}
/**
* Method to obtain an input stream for the given resource.
*
* @param entry the resource entry.
*
* @return the resource content as a stream.
* @throws ResponseContextException if the operation failed.
*/
public InputStream getMediaStream(Resource entry) throws ResponseContextException {
try {
return new ByteArrayInputStream((byte[]) entry.getContent());
} catch (RegistryException e) {
throw new ResponseContextException(new StackTraceResponseContext(e));
}
}
/**
* Generates the feed IRI for the given entry.
*
* @param entryObj the entry object.
* @param request the request context.
*
* @return the feed IRI.
*/
protected String getFeedIriForEntry(Resource entryObj, RequestContext request) {
// We need to build the feed uri manually as the forwarded urls from the tenant url servlet
// filter is causing problem (additional / at the start)in the request.getResolvedUri()
// method
IRI baseUri = request.getBaseUri();
String feedString = baseUri.getScheme() + "://" + baseUri.getAuthority();
IRI requestUri = request.getUri();
String requestUriStr = "";
if (requestUri != null) {
requestUriStr = request.getUri().toString();
// remove the additional '/' character.
if (requestUriStr.length() > 1 &&
requestUriStr.charAt(0) == '/' && requestUriStr.charAt(1) == '/') {
requestUriStr = requestUriStr.substring(1);
} else if (requestUriStr.length() > 0 && requestUriStr.charAt(0) != '/') {
requestUriStr = "/" + requestUriStr;
}
}
return feedString + requestUriStr;
// return request.getResolvedUri().toString();
// setHref(entryObj.getPath());
// String href = getHref(request);
// return getAtomURI(entryObj.getParentPath());
}
/**
* This method will create a SecureRegistry for APP. If the user has send the user name and the
* password then the JDBC registry will be created using the value he has given, else the JDBC
* registry instance will be created as anonymous user.
*
* @param request RequestContext to get the authorization header
*
* @return created JDBC registry instance
* @throws RegistryException If something went wrong
*/
private Registry getSecureRegistry(RequestContext request) throws RegistryException {
Registry reg =
(Registry) request.getAttribute(RequestContext.Scope.REQUEST, "userRegistry");
if (reg == null) {
throw new RegistryException("Couldn't find UserRegistry in RequestContext!");
}
return reg;
}
// Method to generate the resource name.
private synchronized String generateResourceName() {
return "resource" + curResource++;
}
}