Java tutorial
/******************************************************************************* * Copyright 2013 Johns Hopkins University * * Licensed 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 edu.jhu.pha.vosync.rest; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URISyntaxException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import javax.annotation.security.RolesAllowed; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.DefaultValue; import javax.ws.rs.FormParam; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.ResponseBuilder; import javax.ws.rs.core.SecurityContext; import org.apache.commons.configuration.Configuration; import org.apache.commons.lang3.RandomStringUtils; import org.apache.log4j.Logger; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.en.EnglishAnalyzer; import org.apache.lucene.document.Document; import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.queryparser.classic.QueryParser; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.store.Directory; import org.apache.lucene.store.FSDirectory; import org.apache.lucene.util.Version; import org.codehaus.jackson.JsonFactory; import org.codehaus.jackson.JsonGenerationException; import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.map.MappingJsonFactory; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.util.TokenBuffer; import com.sun.jersey.core.header.FormDataContentDisposition; import com.sun.jersey.multipart.FormDataParam; import edu.jhu.pha.vospace.DbPoolServlet; import edu.jhu.pha.vospace.DbPoolServlet.SqlWorker; import edu.jhu.pha.vospace.SettingsServlet; import edu.jhu.pha.vospace.api.AccountInfo; import edu.jhu.pha.vospace.jobs.JobsProcessor; import edu.jhu.pha.vospace.meta.MetaStore; import edu.jhu.pha.vospace.meta.MetaStoreDistributed; import edu.jhu.pha.vospace.meta.MetaStoreFactory; import edu.jhu.pha.vospace.meta.RegionsInfo; import edu.jhu.pha.vospace.node.ContainerNode; import edu.jhu.pha.vospace.node.DataNode; import edu.jhu.pha.vospace.node.Node; import edu.jhu.pha.vospace.node.Node.Detail; import edu.jhu.pha.vospace.node.NodeFactory; import edu.jhu.pha.vospace.node.NodeInfo; import edu.jhu.pha.vospace.node.NodePath; import edu.jhu.pha.vospace.node.NodeType; import edu.jhu.pha.vospace.node.VospaceId; import edu.jhu.pha.vospace.oauth.UserHelper; import edu.jhu.pha.vospace.oauth.SciDriveUser; import edu.jhu.pha.vospace.process.NodeProcessor; import edu.jhu.pha.vospace.process.ProcessorConfig; import edu.jhu.pha.vospace.process.ProcessingFactory; import edu.jhu.pha.vospace.rest.JobDescription; import edu.jhu.pha.vosync.exception.BadRequestException; import edu.jhu.pha.vosync.exception.ForbiddenException; import edu.jhu.pha.vosync.exception.InternalServerErrorException; import edu.jhu.pha.vosync.exception.NotFoundException; import edu.jhu.pha.vosync.meta.Chunk; import edu.jhu.pha.vosync.meta.VoSyncMetaStore; /** * @author Dmitry Mishin */ @Path("/1/") public class DropboxService { private static final Logger logger = Logger.getLogger(DropboxService.class); private @Context SecurityContext security; private static final Configuration conf = SettingsServlet.getConfig(); private static final JsonFactory f = new JsonFactory(); private static final double GIGABYTE = 1024.0 * 1024.0 * 1024.0; @Path("fileops/{op:copy|move}") @POST @RolesAllowed({ "user", "rwshareuser" }) public Response copy(@PathParam("op") String operation, @FormParam("root") String root, @FormParam("from_path") String fromPath, @FormParam("to_path") String toPath) { SciDriveUser user = ((SciDriveUser) security.getUserPrincipal()); boolean keepBytes = operation.equals("copy"); if (null == root || root.isEmpty()) throw new BadRequestException("Not found parameter root"); if (null == fromPath || fromPath.isEmpty()) throw new BadRequestException("Not found parameter fromPath"); if (null == toPath || toPath.isEmpty()) throw new BadRequestException("Not found parameter toPath"); VospaceId fromId, toId; try { fromId = new VospaceId(new NodePath(fromPath, user.getRootContainer())); toId = new VospaceId(new NodePath(toPath, user.getRootContainer())); } catch (URISyntaxException e) { throw new BadRequestException("InvalidURI"); } Node node; try { node = NodeFactory.getNode(fromId, user.getName()); } catch (edu.jhu.pha.vospace.api.exceptions.NotFoundException ex) { throw new NotFoundException(fromId.getNodePath().getNodeStoragePath()); } try { node.copy(toId, keepBytes); } catch (edu.jhu.pha.vospace.api.exceptions.BadRequestException ex) { throw new BadRequestException(ex.getMessage()); } return Response.ok(NodeFactory.getNode(toId, user.getName()).export("json-dropbox", Detail.min)).build(); } @Path("fileops/create_folder") @POST @RolesAllowed({ "user", "rwshareuser" }) public Response createFolder(@FormParam("root") String root, @FormParam("path") String path) { logger.debug("Creating folder " + path); SciDriveUser user = ((SciDriveUser) security.getUserPrincipal()); if (null == root || root.isEmpty()) throw new BadRequestException("Not found parameter root"); if (null == path) throw new BadRequestException("Not found parameter path"); VospaceId identifier; try { identifier = new VospaceId(new NodePath(path, user.getRootContainer())); } catch (URISyntaxException e) { throw new BadRequestException("InvalidURI"); } Node node = NodeFactory.createNode(identifier, user.getName(), NodeType.CONTAINER_NODE); node.createParent(); node.setNode(null); return Response.ok(node.export("json-dropbox", Detail.min)).build(); } @Path("fileops/delete") @POST @RolesAllowed({ "user", "rwshareuser" }) public Response delete(@FormParam("root") String root, @FormParam("path") String path) { SciDriveUser user = ((SciDriveUser) security.getUserPrincipal()); if (null == root || root.isEmpty()) throw new BadRequestException("Not found parameter root"); if (null == path || path.isEmpty()) throw new BadRequestException("Not found parameter path"); VospaceId identifier; try { identifier = new VospaceId(new NodePath(path, user.getRootContainer())); } catch (URISyntaxException e) { throw new BadRequestException("InvalidURI"); } Node node; try { node = NodeFactory.getNode(identifier, user.getName()); } catch (edu.jhu.pha.vospace.api.exceptions.NotFoundException ex) { throw new NotFoundException(identifier.getNodePath().getNodeStoragePath()); } node.markRemoved(true); return Response.ok(NodeFactory.getNode(identifier, user.getName()).export("json-dropbox", Detail.min)) .build(); } @GET @Path("account/info") @RolesAllowed({ "user", "rwshareuser", "roshareuser" }) public Response getAccountInfo() { SciDriveUser user = ((SciDriveUser) security.getUserPrincipal()); try { ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); JsonGenerator g2 = f.createJsonGenerator(byteOut).useDefaultPrettyPrinter(); AccountInfo info = UserHelper.getAccountInfo(user.getName()); g2.writeStartObject(); g2.writeStringField("referral_link", ""); g2.writeStringField("display_name", info.getUsername()); g2.writeStringField("uid", "0"); g2.writeStringField("country", "US"); g2.writeFieldName("quota_info"); g2.writeStartObject(); g2.writeNumberField("shared", 0); g2.writeNumberField("quota", info.getSoftLimit() * GIGABYTE); g2.writeNumberField("normal", info.getBytesUsed()); g2.writeEndObject(); g2.writeArrayFieldStart("services"); JsonNode servicesCredentials = UserHelper.getUserServices(user.getName()); for (ProcessorConfig proc : ProcessingFactory.getInstance().getProcessorConfigs().values()) { g2.writeStartObject(); g2.writeStringField("id", proc.getId()); g2.writeStringField("title", proc.getTitle()); g2.writeBooleanField("enabled", null != servicesCredentials.get(proc.getId())); g2.writeEndObject(); } g2.writeEndArray(); g2.close(); byteOut.close(); return Response.ok(byteOut.toByteArray()).build(); } catch (IOException ex) { throw new InternalServerErrorException(ex.getMessage()); } } @PUT @Path("account/service/{processor:.+}") @RolesAllowed({ "user" }) public Response setAccountService(InputStream serviceCredInpStream, @PathParam("processor") String processor) { SciDriveUser user = ((SciDriveUser) security.getUserPrincipal()); try { ObjectMapper mapper = new ObjectMapper(); JsonNode credNode = mapper.readTree(serviceCredInpStream); UserHelper.updateUserService(user.getName(), processor, credNode); return Response.ok().build(); } catch (IOException ex) { throw new InternalServerErrorException(ex.getMessage()); } } @DELETE @Path("account/service/{processor:.+}") @RolesAllowed({ "user" }) public Response disableAccountService(@PathParam("processor") String processor) { SciDriveUser user = ((SciDriveUser) security.getUserPrincipal()); UserHelper.updateUserService(user.getName(), processor, null); return Response.ok().build(); } @GET @Path("account/service/{processor:.+}") @RolesAllowed({ "user" }) public Response getAccountService(@PathParam("processor") String processor) { SciDriveUser user = ((SciDriveUser) security.getUserPrincipal()); JsonNode node = UserHelper.getUserServices(user.getName()); String cred = (node.get(processor) == null) ? "{}" : node.get(processor).toString(); return Response.ok(cred).build(); } @GET @Path("account/service_schema/{processor:.+}") public Response getAccountServiceSchema(@PathParam("processor") String processor) { ProcessorConfig config = ProcessingFactory.getInstance().getProcessorConfigs().get(processor); if (config == null) throw new NotFoundException("Processor not found"); return Response.ok(config.getSchemaAsJson()).build(); } @GET @Path("regions/info") @RolesAllowed({ "user" }) public Response getRegionsInfo() { MetaStore mstore = MetaStoreFactory.getMetaStore(null); if (mstore instanceof MetaStoreDistributed) { RegionsInfo regionsInfo = ((MetaStoreDistributed) mstore).getRegionsInfo(); return Response.ok(regionsInfo.toJson()).build(); } throw new InternalServerErrorException("Unsupported"); } @GET @Path("files/{root:dropbox|sandbox}/{path:.+}") @RolesAllowed({ "user", "rwshareuser", "roshareuser" }) public Response getFile(@PathParam("root") String root, @PathParam("path") String fullPath) { SciDriveUser user = ((SciDriveUser) security.getUserPrincipal()); VospaceId identifier; try { identifier = new VospaceId(new NodePath(fullPath, user.getRootContainer())); } catch (URISyntaxException e) { throw new BadRequestException("InvalidURI"); } Node node; try { node = NodeFactory.getNode(identifier, user.getName()); } catch (edu.jhu.pha.vospace.api.exceptions.NotFoundException ex) { throw new NotFoundException(identifier.getNodePath().getNodeStoragePath()); } InputStream nodeInputStream; try { nodeInputStream = node.exportData(); } catch (edu.jhu.pha.vospace.api.exceptions.NotFoundException ex) { logger.error("Node " + node.getUri().toString() + " data not found."); throw new NotFoundException(identifier.getId().toASCIIString()); } logger.debug("Node " + node.getUri().toString() + " size: " + node.getNodeInfo().getSize()); ResponseBuilder response = Response.ok(nodeInputStream); response.header("x-dropbox-metadata", new String((byte[]) (node.export("json-dropbox", Detail.min)))); response.header("Content-Disposition", "attachment; filename=" + identifier.getNodePath().getNodeName()); response.header("Content-Length", Long.toString(node.getNodeInfo().getSize())); return response.build(); } @GET @Path("regions/{path:.+}") @RolesAllowed({ "user" }) public Response getFileRegions(@PathParam("path") String fullPath) { SciDriveUser user = ((SciDriveUser) security.getUserPrincipal()); VospaceId identifier; try { identifier = new VospaceId(new NodePath(fullPath, user.getRootContainer())); } catch (URISyntaxException e) { throw new BadRequestException("InvalidURI"); } Node node; try { node = NodeFactory.getNode(identifier, user.getName()); } catch (edu.jhu.pha.vospace.api.exceptions.NotFoundException ex) { throw new NotFoundException(identifier.getNodePath().getNodeStoragePath()); } if (node.getType() == NodeType.CONTAINER_NODE) { List<String> nodeRegions = ((ContainerNode) node).getNodeRegions(); StringBuilder builder = new StringBuilder(); builder.append("["); boolean first = true; for (String region : nodeRegions) { if (!first) builder.append(","); else first = false; builder.append("{\"id\": \"" + region + "\"}"); } builder.append("]"); return Response.ok(builder.toString()).build(); } else { throw new BadRequestException("ContainerNotFound"); } } @GET @Path("metadata/{root:dropbox|sandbox}/{path:.+}") @RolesAllowed({ "user", "rwshareuser", "roshareuser" }) public Response getFileMetadata(@PathParam("root") String root, @PathParam("path") String fullPath, @QueryParam("list") @DefaultValue("true") Boolean list, @QueryParam("file_limit") @DefaultValue("25000") int file_limit, @QueryParam("start") @DefaultValue("0") int start, @QueryParam("count") @DefaultValue("-1") int count, @QueryParam("include_deleted") @DefaultValue("false") boolean includeDeleted) { logger.debug(includeDeleted); SciDriveUser user = ((SciDriveUser) security.getUserPrincipal()); VospaceId identifier; try { identifier = new VospaceId(new NodePath(fullPath, user.getRootContainer())); } catch (URISyntaxException e) { logger.debug(e.getMessage()); throw new BadRequestException("InvalidURI"); } Node node; try { node = NodeFactory.getNode(identifier, user.getName()); } catch (edu.jhu.pha.vospace.api.exceptions.NotFoundException ex) { throw new NotFoundException(identifier.getNodePath().getNodeStoragePath()); } Detail detailLevel = list ? Detail.max : Detail.min; long time = System.currentTimeMillis(); byte[] nodeExport; try { if (node.getType() == NodeType.CONTAINER_NODE) { nodeExport = (byte[]) (((ContainerNode) node).export("json-dropbox", detailLevel, start, count, includeDeleted)); } else { nodeExport = (byte[]) (node.export("json-dropbox", detailLevel)); } } catch (edu.jhu.pha.vospace.api.exceptions.NotFoundException ex) { throw new NotFoundException(identifier.getId().toASCIIString()); } logger.debug("Generated node contents in " + (System.currentTimeMillis() - time) / 1000.0); return Response.ok(nodeExport).build(); } @GET @Path("metadata/{root:dropbox|sandbox}") @RolesAllowed({ "user", "rwshareuser", "roshareuser" }) public Response getRootMetadata(@PathParam("root") String root, @QueryParam("list") @DefaultValue("true") Boolean list, @QueryParam("include_deleted") @DefaultValue("false") boolean includeDeleted) { return getFileMetadata(root, "", list, 25000, 0, -1, includeDeleted); } @GET @Path("transfers/info") @Produces(MediaType.APPLICATION_JSON) @RolesAllowed({ "user" }) public byte[] getTransfersInfo() { final SciDriveUser user = ((SciDriveUser) security.getUserPrincipal()); return DbPoolServlet.goSql("Get transfers queue", "select state, direction, starttime, endtime, target from jobs JOIN user_identities ON jobs.user_id = user_identities.user_id WHERE identity = ? order by starttime DESC", new SqlWorker<byte[]>() { @Override public byte[] go(Connection conn, PreparedStatement stmt) throws SQLException { stmt.setString(1, user.getName()); ByteArrayOutputStream byteOut = null; try { JsonFactory f = new JsonFactory(); byteOut = new ByteArrayOutputStream(); JsonGenerator g2 = f.createJsonGenerator(byteOut); g2.writeStartArray(); ResultSet resSet = stmt.executeQuery(); while (resSet.next()) { g2.writeStartObject(); g2.writeStringField("state", resSet.getString("state")); g2.writeStringField("direction", resSet.getString("direction")); g2.writeStringField("starttime", (null != resSet.getTimestamp("starttime") ? resSet.getTimestamp("starttime").toString() : "")); g2.writeStringField("endtime", (null != resSet.getTimestamp("endtime") ? resSet.getTimestamp("starttime").toString() : "")); g2.writeStringField("path", resSet.getString("target")); g2.writeEndObject(); } g2.writeEndArray(); g2.close(); byteOut.close(); return byteOut.toByteArray(); } catch (IOException ex) { throw new InternalServerErrorException(ex); } } }); } /** * Returns the transfer error representation * @param jobId Job identifier * @return transfer representation */ @GET @Path("transfers/{jobid}/error") @Produces(MediaType.TEXT_PLAIN) @RolesAllowed({ "user" }) public String getTransferErrorDetails(@PathParam("jobid") String jobId) { JobDescription job = JobsProcessor.getJob(UUID.fromString(jobId)); StringBuffer errorDescr = new StringBuffer(); if (null == job) errorDescr.append("The job " + jobId + " is not found.\n"); else errorDescr.append(job.getNote()); return errorDescr.toString(); } @POST @Path("files/{root:dropbox|sandbox}/{path:.+}") @Consumes(MediaType.MULTIPART_FORM_DATA) /*TODO Test the method */ @RolesAllowed({ "user", "rwshareuser" }) public Response postFile(@PathParam("root") String root, @PathParam("path") String fullPath, @FormDataParam("file") InputStream fileDataInp, @FormDataParam("file") FormDataContentDisposition fileDetail, @QueryParam("overwrite") @DefaultValue("true") Boolean overwrite) { SciDriveUser user = ((SciDriveUser) security.getUserPrincipal()); if (!user.isWriteEnabled()) { throw new ForbiddenException("ReadOnly"); } VospaceId identifier; try { identifier = new VospaceId(new NodePath(fullPath, user.getRootContainer())); } catch (URISyntaxException e) { throw new BadRequestException("InvalidURI"); } MetaStore metastore = MetaStoreFactory.getMetaStore(user.getName()); Node node; if (identifier.getNodePath().getParentPath().isRoot(false)) { throw new NotFoundException("Is a root folder"); } else { if (!overwrite) { if (metastore.isStored(identifier)) { logger.debug("Found conflict in node " + identifier); String currentFile = identifier.toString(); String fileName = currentFile.substring(currentFile.lastIndexOf("/") + 1); if (fileName.contains(".")) fileName = fileName.substring(0, fileName.lastIndexOf('.')); int current_num = 1; try { VospaceId newId = new VospaceId( currentFile.replaceAll(fileName, fileName + "_" + current_num++)); while (metastore.isStored(newId)) { logger.debug("Node " + newId.toString() + " exists."); newId = new VospaceId(currentFile.replaceAll(fileName, fileName + "_" + current_num++)); } logger.debug("Node " + newId.toString() + " not exists."); node = (DataNode) NodeFactory.createNode(newId, user.getName(), NodeType.DATA_NODE); node.createParent(); node.setNode(null); } catch (URISyntaxException e) { throw new InternalServerErrorException("InvalidURI"); } } else { node = (DataNode) NodeFactory.createNode(identifier, user.getName(), NodeType.DATA_NODE); node.createParent(); node.setNode(null); } } else { try { node = NodeFactory.getNode(identifier, user.getName()); } catch (NotFoundException ex) { node = (DataNode) NodeFactory.createNode(identifier, user.getName(), NodeType.DATA_NODE); node.createParent(); node.setNode(null); } } } if (!(node instanceof DataNode)) { throw new NotFoundException("Is a container"); } ((DataNode) node).setData(fileDataInp); return Response.ok(node.export("json-dropbox", Detail.max)).build(); } @PUT @Path("files_put/{root:dropbox|sandbox}/{path:.+}") @RolesAllowed({ "user", "rwshareuser" }) public Response putFile(@PathParam("root") String root, @PathParam("path") String fullPath, InputStream fileDataInp, @QueryParam("overwrite") @DefaultValue("true") Boolean overwrite, @QueryParam("parent_rev") String parentRev) { SciDriveUser user = ((SciDriveUser) security.getUserPrincipal()); VospaceId identifier; try { identifier = new VospaceId(new NodePath(fullPath, user.getRootContainer())); } catch (URISyntaxException e) { throw new BadRequestException("InvalidURI"); } MetaStore metastore = MetaStoreFactory.getMetaStore(user.getName()); Node node; if (identifier.getNodePath().getParentPath().isRoot(false)) { throw new NotFoundException("Is a root folder"); } else { if (parentRev != null) { if (metastore.isStored(identifier)) { //throw new BadRequestException(identifier.toString()+" exists."); //logger.debug("Found conflict in node "+identifier); node = NodeFactory.getNode(identifier, user.getName()); if (!parentRev.equals(Integer.toString(node.getNodeInfo().getRevision()))) { throw new BadRequestException( "Revision mismatch: current is " + node.getNodeInfo().getRevision()); //TODO fix the revisions /*logger.debug("Revisions do not match: "+parentRev+" "+node.getNodeInfo().getCurrentRev()); String currentFile = identifier.toString(); String fileName = currentFile.substring(currentFile.lastIndexOf("/")+1); if(fileName.contains(".")) fileName = fileName.substring(0,fileName.lastIndexOf('.')); int current_num = 1; try { VospaceId newId = new VospaceId(currentFile.replaceAll(fileName, fileName+"_"+current_num++)); while(metastore.isStored(newId)){ newId = new VospaceId(currentFile.replaceAll(fileName, fileName+"_"+current_num++)); } node = (DataNode)NodeFactory.getDefaultNode(newId, username); node.createParent(); node.setNode(); } catch(URISyntaxException e) { throw new InternalServerErrorException("InvalidURI"); }*/ } } else { node = (DataNode) NodeFactory.createNode(identifier, user.getName(), NodeType.DATA_NODE); node.createParent(); node.setNode(null); } } else { if (metastore.isStored(identifier)) { Node tmpNode = NodeFactory.getNode(identifier, user.getName()); tmpNode.getStorage().remove(tmpNode.getUri().getNodePath(), true); tmpNode.getMetastore().remove(tmpNode.getUri()); } node = (DataNode) NodeFactory.createNode(identifier, user.getName(), NodeType.DATA_NODE); node.createParent(); node.setNode(null); } } if (!(node instanceof DataNode)) { throw new NotFoundException("Node is a container"); } ((DataNode) node).setData(fileDataInp); Response resp = Response.ok(node.export("json-dropbox", Detail.max)).build(); return resp; } @Path("search/{root:dropbox|sandbox}/{path:.+}") @GET @RolesAllowed({ "user", "rwshareuser", "roshareuser" }) public byte[] search(@PathParam("root") String root, @PathParam("path") String fullPath, @QueryParam("query") String query, @QueryParam("file_limit") @DefaultValue("1000") int fileLimit, @QueryParam("include_deleted") @DefaultValue("false") boolean includeDeleted) { SciDriveUser user = ((SciDriveUser) security.getUserPrincipal()); if (null == query || query.length() < 3) { throw new BadRequestException("Wrong query parameter"); } VospaceId identifier; try { identifier = new VospaceId(new NodePath(fullPath, user.getRootContainer())); } catch (URISyntaxException e) { throw new BadRequestException("InvalidURI"); } Node node; try { node = NodeFactory.getNode(identifier, user.getName()); } catch (edu.jhu.pha.vospace.api.exceptions.NotFoundException ex) { throw new NotFoundException(identifier.getNodePath().getNodeStoragePath()); } if (!(node instanceof ContainerNode)) { throw new NotFoundException("Not a container"); } List<VospaceId> nodesList = ((ContainerNode) node).search(query, fileLimit, includeDeleted); TokenBuffer g = new TokenBuffer(null); try { g.writeStartArray(); for (VospaceId childNodeId : nodesList) { Node childNode = NodeFactory.getNode(childNodeId, user.getName()); JsonNode jnode = (JsonNode) childNode.export("json-dropbox-object", Detail.min); g.writeTree(jnode); /*CharBuffer cBuffer = Charset.forName("ISO-8859-1").decode(ByteBuffer.wrap((byte[])childNode.export("json-dropbox", Detail.min))); while(cBuffer.remaining() > 0) g.writeRaw(cBuffer.get()); if(ind++ < nodesList.size()-1) g.writeRaw(',');*/ } g.writeEndArray(); ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); MappingJsonFactory f = new MappingJsonFactory(); JsonGenerator g2 = f.createJsonGenerator(byteOut).useDefaultPrettyPrinter(); g.serialize(g2); g2.close(); byteOut.close(); return byteOut.toByteArray(); } catch (JsonGenerationException e) { e.printStackTrace(); throw new InternalServerErrorException("Error generationg JSON: " + e.getMessage()); } catch (IOException e) { e.printStackTrace(); throw new InternalServerErrorException("Error generationg JSON: " + e.getMessage()); } finally { try { g.close(); } catch (IOException ex) { } } } @Path("cont_search") @GET @RolesAllowed({ "user", "rwshareuser" }) public Response contSearch(@QueryParam("query") String queryStr) { SciDriveUser user = ((SciDriveUser) security.getUserPrincipal()); try { Directory directory = FSDirectory.open(new File(conf.getString("lucene.index"))); DirectoryReader ireader = DirectoryReader.open(directory); IndexSearcher isearcher = new IndexSearcher(ireader); Analyzer analyzer = new EnglishAnalyzer(Version.LUCENE_41); QueryParser parser = new QueryParser(Version.LUCENE_41, "content", analyzer); String queryFullStr = "owner:\"" + user.getName() + "\" AND " + queryStr; Query query = parser.parse(queryFullStr); ScoreDoc[] hits = isearcher.search(query, null, 100).scoreDocs; StringBuffer buf = new StringBuffer(); buf.append("<p>Results: " + hits.length + "</p>"); for (int i = 0; i < hits.length; i++) { Document hitDoc = isearcher.doc(hits[i].doc); buf.append("<h3>" + hitDoc.get("source") + "</h3>"); if (hitDoc.get("content").length() > 1024) buf.append("<p>" + hitDoc.get("content").substring(0, 1024) + "...</p>"); else buf.append("<p>" + hitDoc.get("content") + "</p>"); } analyzer.close(); ireader.close(); directory.close(); return Response.ok(buf.toString()).build(); } catch (Exception ex) { ex.printStackTrace(); return Response.ok().build(); } } @PUT @Path("regions_put/{path:.+}") @RolesAllowed({ "user" }) public Response putFileRegions(@PathParam("path") String fullPath, InputStream regionsInpStream) { SciDriveUser user = ((SciDriveUser) security.getUserPrincipal()); VospaceId identifier; try { identifier = new VospaceId(new NodePath(fullPath, user.getRootContainer())); } catch (URISyntaxException e) { throw new BadRequestException("InvalidURI"); } Node node; try { node = NodeFactory.getNode(identifier, user.getName()); } catch (edu.jhu.pha.vospace.api.exceptions.NotFoundException ex) { throw new NotFoundException(identifier.getNodePath().getNodeStoragePath()); } if (node.getType() == NodeType.CONTAINER_NODE) { try { Map<String, String> regions = new HashMap<String, String>(); BufferedReader bufferedRead = new BufferedReader(new InputStreamReader(regionsInpStream)); String curRegion = bufferedRead.readLine(); String firstRegion = new String(curRegion); if (null == curRegion) throw new BadRequestException("No regions defined"); String syncRegion = bufferedRead.readLine(); do { regions.put(curRegion, syncRegion); if (null != syncRegion) { curRegion = new String(syncRegion); syncRegion = bufferedRead.readLine(); } } while (null != syncRegion); if (null != regions.get(firstRegion)) { regions.put(curRegion, firstRegion); } bufferedRead.close(); ((ContainerNode) node).setNodeRegions(regions); return Response.ok().build(); } catch (IOException ex) { throw new InternalServerErrorException("Error reading PUT request"); } } else { throw new BadRequestException("ContainerNotFound"); } } /** * Create new share * @param root * @param fullPath * @param group * @param write_perm * @return */ @PUT @Path("shares/{root:dropbox|sandbox}/{path:.+}") @RolesAllowed({ "user" }) public byte[] putShares(@PathParam("root") String root, @PathParam("path") String fullPath, @QueryParam("group") String group, @DefaultValue("false") @QueryParam("write_perm") Boolean write_perm) { SciDriveUser user = ((SciDriveUser) security.getUserPrincipal()); VospaceId identifier; try { identifier = new VospaceId(new NodePath(fullPath, user.getRootContainer())); } catch (URISyntaxException e) { logger.debug(e.getMessage()); throw new BadRequestException("InvalidURI"); } Node node; try { node = NodeFactory.getNode(identifier, user.getName()); } catch (edu.jhu.pha.vospace.api.exceptions.NotFoundException ex) { throw new NotFoundException(identifier.getNodePath().getNodeStoragePath()); } ByteArrayOutputStream byteOut = null; try { JsonFactory f = new JsonFactory(); byteOut = new ByteArrayOutputStream(); JsonGenerator g2 = f.createJsonGenerator(byteOut); g2.writeStartObject(); g2.writeStringField("id", node.getMetastore().createShare(node.getUri(), group, write_perm)); g2.writeStringField("uri", ""); g2.writeStringField("expires", "never"); g2.writeEndObject(); g2.close(); byteOut.close(); return byteOut.toByteArray(); } catch (IOException ex) { throw new InternalServerErrorException(ex); } } @GET @Path("shares") @RolesAllowed({ "user" }) public byte[] getShares() { final SciDriveUser user = ((SciDriveUser) security.getUserPrincipal()); ByteArrayOutputStream byteOut = null; try { JsonFactory f = new JsonFactory(); byteOut = new ByteArrayOutputStream(); final JsonGenerator g2 = f.createJsonGenerator(byteOut); g2.writeStartArray(); DbPoolServlet.goSql("Get shares", "select share_id, container_name, group_name, share_write_permission FROM container_shares " + "LEFT JOIN groups ON container_shares.group_id = groups.group_id " + "JOIN containers ON container_shares.container_id = containers.container_id " + "JOIN user_identities ON containers.user_id = user_identities.user_id WHERE identity = ?", new SqlWorker<Boolean>() { @Override public Boolean go(Connection conn, PreparedStatement stmt) throws SQLException { stmt.setString(1, user.getName()); ResultSet rs = stmt.executeQuery(); while (rs.next()) { try { g2.writeStartObject(); g2.writeStringField("share_id", rs.getString("share_id")); g2.writeStringField("container", rs.getString("container_name")); g2.writeStringField("group", rs.getString("group_name")); g2.writeBooleanField("write_permission", rs.getBoolean("share_write_permission")); g2.writeEndObject(); } catch (IOException ex) { logger.error(ex.getMessage()); } } return true; } }); g2.writeEndArray(); g2.close(); byteOut.close(); return byteOut.toByteArray(); } catch (IOException ex) { throw new InternalServerErrorException(ex); } } @DELETE @Path("shares/{share_id:.+}") @RolesAllowed({ "user", "rwshareuser" }) public Response deleteShare(@PathParam("share_id") final String share_id) { final SciDriveUser user = ((SciDriveUser) security.getUserPrincipal()); DbPoolServlet.goSql("Remove share", "delete container_shares from container_shares " + "JOIN containers ON container_shares.container_id = containers.container_id " + "JOIN user_identities ON containers.user_id = user_identities.user_id WHERE share_id = ? AND identity = ?;", new SqlWorker<Boolean>() { @Override public Boolean go(Connection conn, PreparedStatement stmt) throws SQLException { stmt.setString(1, share_id); stmt.setString(2, user.getName()); return stmt.execute(); } }); return Response.ok().build(); } @Path("share_groups") @GET @RolesAllowed({ "user", "rwshareuser", "roshareuser" }) public byte[] shareGroups() { ByteArrayOutputStream byteOut = null; try { JsonFactory f = new JsonFactory(); byteOut = new ByteArrayOutputStream(); final JsonGenerator g2 = f.createJsonGenerator(byteOut); g2.writeStartArray(); DbPoolServlet.goSql("Get share groups", "select group_id, group_name from groups order by group_name;", new SqlWorker<Boolean>() { @Override public Boolean go(Connection conn, PreparedStatement stmt) throws SQLException { ResultSet rs = stmt.executeQuery(); while (rs.next()) { try { g2.writeStartObject(); g2.writeNumberField("id", rs.getInt(1)); g2.writeStringField("name", rs.getString(2)); g2.writeEndObject(); } catch (IOException ex) { logger.error(ex.getMessage()); } } return true; } }); g2.writeEndArray(); g2.close(); byteOut.close(); return byteOut.toByteArray(); } catch (IOException ex) { throw new InternalServerErrorException(ex); } } @Path("share_groups/{group_id}") @GET @RolesAllowed({ "user", "rwshareuser", "roshareuser" }) public byte[] shareGroupMembers(@PathParam("group_id") final int group_id) { ByteArrayOutputStream byteOut = null; try { JsonFactory f = new JsonFactory(); byteOut = new ByteArrayOutputStream(); final JsonGenerator g2 = f.createJsonGenerator(byteOut); g2.writeStartArray(); DbPoolServlet.goSql("Get share group members", "select identity from user_identities JOIN user_groups ON user_identities.user_id = user_groups.user_id WHERE group_id = ? order by identity;", new SqlWorker<Boolean>() { @Override public Boolean go(Connection conn, PreparedStatement stmt) throws SQLException { stmt.setInt(1, group_id); ResultSet rs = stmt.executeQuery(); while (rs.next()) { try { g2.writeString(rs.getString(1)); } catch (IOException ex) { logger.error(ex.getMessage()); } } return true; } }); g2.writeEndArray(); g2.close(); byteOut.close(); return byteOut.toByteArray(); } catch (IOException ex) { throw new InternalServerErrorException(ex); } } @Path("media/{root:dropbox|sandbox}/{path:.+}") @GET @RolesAllowed({ "user", "rwshareuser", "roshareuser" }) public Response media(@PathParam("root") String root, @PathParam("path") String fullPath) { SciDriveUser user = ((SciDriveUser) security.getUserPrincipal()); VospaceId identifier; try { identifier = new VospaceId(new NodePath(fullPath, user.getRootContainer())); } catch (URISyntaxException e) { logger.debug(e.getMessage()); throw new BadRequestException("InvalidURI"); } Node node; try { node = NodeFactory.getNode(identifier, user.getName()); } catch (edu.jhu.pha.vospace.api.exceptions.NotFoundException ex) { throw new NotFoundException(identifier.getNodePath().getNodeStoragePath()); } if (!(node instanceof DataNode)) { throw new BadRequestException("Invalid NodeType"); } try { ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); JsonGenerator g2 = f.createJsonGenerator(byteOut).useDefaultPrettyPrinter(); g2.writeStartObject(); g2.writeStringField("url", ((DataNode) node).getHttpDownloadLink().toASCIIString()); g2.writeStringField("expires", "never (yet)"); g2.writeEndObject(); g2.close(); byteOut.close(); return Response.ok(byteOut.toByteArray()).build(); } catch (Exception e) { throw new InternalServerErrorException(e.getMessage()); } } @Path("chunked_upload") @PUT @RolesAllowed({ "user", "rwshareuser" }) public Response chunkedUpload(@QueryParam("upload_id") String uploadId, @QueryParam("offset") long offset, InputStream fileDataInp) { final SciDriveUser user = ((SciDriveUser) security.getUserPrincipal()); VoSyncMetaStore voMeta = new VoSyncMetaStore(user.getName()); logger.debug("New chunk: " + uploadId + " " + offset); if (null == uploadId) { uploadId = RandomStringUtils.randomAlphanumeric(15); } Chunk newChunk = voMeta.getLastChunk(uploadId); if (offset != newChunk.getChunkStart()) { // return error with proper offset logger.error("Wrong offset: " + offset + " should be:" + newChunk.getChunkStart()); ResponseBuilder errorResp = Response.status(400); errorResp.entity(genChunkResponse(uploadId, newChunk.getChunkStart())); return errorResp.build(); } VospaceId identifier; try { String chunkNumberString = String.format("%07d", newChunk.getChunkNum()); identifier = new VospaceId(new NodePath( "/" + conf.getString("chunked_container") + "/" + uploadId + "/" + chunkNumberString)); DataNode node = (DataNode) NodeFactory.createNode(identifier, user.getName(), NodeType.DATA_NODE); node.getStorage().createContainer(new NodePath("/" + conf.getString("chunked_container"))); node.getStorage().putBytes(identifier.getNodePath(), fileDataInp); NodeInfo info = new NodeInfo(); node.getStorage().updateNodeInfo(identifier.getNodePath(), info); node.setNodeInfo(info); newChunk.setSize(info.getSize()); voMeta.putNewChunk(newChunk); byte[] resp = genChunkResponse(uploadId, newChunk.getChunkStart() + newChunk.getSize()); return Response.ok(resp).build(); } catch (URISyntaxException e) { e.printStackTrace(); throw new InternalServerErrorException(e.getMessage()); } } @Path("commit_chunked_upload/{root:dropbox|sandbox}/{path:.+}") @POST @RolesAllowed({ "user", "rwshareuser" }) public Response commitChunkedUpload(@PathParam("root") String root, @PathParam("path") String fullPath, @FormParam("upload_id") String uploadId, @QueryParam("overwrite") @DefaultValue("true") Boolean overwrite, @QueryParam("parent_rev") String parentRev) { final SciDriveUser user = ((SciDriveUser) security.getUserPrincipal()); VoSyncMetaStore vosyncMeta = new VoSyncMetaStore(user.getName()); if (null == uploadId || !(vosyncMeta.chunkedExists(uploadId))) { throw new BadRequestException("Parameter upload_id is missing or invalid"); } VospaceId identifier; try { identifier = new VospaceId(new NodePath(fullPath, user.getRootContainer())); } catch (URISyntaxException e) { throw new BadRequestException("InvalidURI"); } MetaStore metastore = MetaStoreFactory.getMetaStore(user.getName()); Node node; if (identifier.getNodePath().getParentPath().isRoot(false)) { throw new NotFoundException("Is a root folder"); } else { if (parentRev != null) { if (metastore.isStored(identifier)) { node = NodeFactory.getNode(identifier, user.getName()); if (!parentRev.equals(Integer.toString(node.getNodeInfo().getRevision()))) { throw new BadRequestException( "Revision mismatch: current is " + node.getNodeInfo().getRevision()); //TODO fix the revisions } } else { node = (DataNode) NodeFactory.createNode(identifier, user.getName(), NodeType.DATA_NODE); node.createParent(); node.setNode(null); } } else { try { node = NodeFactory.getNode(identifier, user.getName()); if (!overwrite) { throw new BadRequestException("Node exists"); } } catch (edu.jhu.pha.vospace.api.exceptions.NotFoundException ex) { node = (DataNode) NodeFactory.createNode(identifier, user.getName(), NodeType.DATA_NODE); node.createParent(); node.setNode(null); } } } if (!(node instanceof DataNode)) { throw new NotFoundException("Node is a container"); } if (node.getNodeInfo().isDeleted()) { node.markRemoved(false); } ((DataNode) node).setChunkedData(uploadId); Response resp = Response.ok(node.export("json-dropbox", Detail.max)).build(); return resp; } private static byte[] genChunkResponse(String uploadId, long offset) { try { ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); JsonGenerator g2 = f.createJsonGenerator(byteOut).useDefaultPrettyPrinter(); g2.writeStartObject(); g2.writeStringField("upload_id", uploadId); g2.writeNumberField("offset", offset);//31337 g2.writeStringField("expires", "Tue, 19 Jul 2014 21:55:38 +0000");//"Tue, 19 Jul 2011 21:55:38 +0000" g2.writeEndObject(); g2.close(); byteOut.close(); return byteOut.toByteArray(); } catch (JsonGenerationException e) { throw new InternalServerErrorException(e.getMessage()); } catch (IOException e) { throw new InternalServerErrorException(e.getMessage()); } } }