/** * Copyright 2011 Intuit Inc. All Rights Reserved */ package com.intuit.tank.service.impl.v1.datafile; /* * #%L * Datafile Rest Service * %% * Copyright (C) 2011 - 2015 Intuit Inc. * %% * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * #L% */ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import javax.ws.rs.Path; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.ResponseBuilder; import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.StreamingOutput; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import org.apache.commons.io.IOUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import com.intuit.tank.api.model.v1.datafile.DataFileDescriptor; import com.intuit.tank.api.model.v1.datafile.DataFileDescriptorContainer; import com.intuit.tank.dao.DataFileDao; import com.intuit.tank.datafile.util.DataFileServiceUtil; import com.intuit.tank.project.DataFile; import com.intuit.tank.service.api.v1.DataFileService; import com.intuit.tank.service.util.ResponseUtil; import com.intuit.tank.storage.FileData; import com.intuit.tank.storage.FileStorage; import com.intuit.tank.storage.FileStorageFactory; import com.intuit.tank.util.DataFileUtil; import com.intuit.tank.vm.settings.TankConfig; import com.sun.jersey.multipart.FormDataBodyPart; import com.sun.jersey.multipart.FormDataMultiPart; /** * DataFileServiceV1 * * @author dangleton * */ @Path(DataFileService.SERVICE_RELATIVE_PATH) public class DataFileServiceV1 implements DataFileService { private static final Logger LOG = LogManager.getLogger(DataFileServiceV1.class); /** * @{inheritDoc */ @Override public String ping() { return "PONG " + getClass().getSimpleName(); } /** * @{inheritDoc */ @Override public StreamingOutput getDataFileData(Integer id) { return getDataFileVersion(id, null, 0, -1); } /** * @{inheritDoc */ @Override public StreamingOutput getDataFileDataOffset(Integer id, int offset, int numLines) { return getDataFileVersion(id, null, offset, numLines); } /** * @{inheritDoc */ @Override public StreamingOutput getDataFileVersion(Integer id, Integer version, final int offset, final int numLines) { DataFileDao dataFileDao = new DataFileDao(); DataFile dataFile = dataFileDao.findById(id); return getStreamingOutput(offset, numLines, dataFile); } /** * @{inheritDoc */ @Override public Response saveOrUpdateDataFile(FormDataMultiPart formData) { DataFile dataFile = null; InputStream is = null; Map<String, List<FormDataBodyPart>> fields = formData.getFields(); DataFileDao dao = new DataFileDao(); for (Entry<String, List<FormDataBodyPart>> entry : fields.entrySet()) { String formName = entry.getKey(); LOG.debug("Entry name: " + formName); for (FormDataBodyPart part : entry.getValue()) { MediaType mediaType = part.getMediaType(); if (MediaType.APPLICATION_XML_TYPE.equals(mediaType) || MediaType.APPLICATION_JSON_TYPE.equals(mediaType)) { DataFileDescriptor dfd = part.getEntityAs(DataFileDescriptor.class); dataFile = descriptorToDataFile(dao, dfd); } else if (MediaType.TEXT_PLAIN_TYPE.equals(mediaType)) { String s = part.getEntityAs(String.class); LOG.debug("Plain Text Value: " + s); if ("xmlString".equalsIgnoreCase(formName)) { try { JAXBContext ctx = JAXBContext.newInstance(DataFileDescriptor.class.getPackage().getName()); DataFileDescriptor dfd = (DataFileDescriptor) ctx.createUnmarshaller().unmarshal( new StringReader(s)); dataFile = descriptorToDataFile(dao, dfd); } catch (JAXBException e) { throw new RuntimeException(e); } } } else if (MediaType.APPLICATION_OCTET_STREAM_TYPE.equals(mediaType)) { // get the file is = part.getValueAs(InputStream.class); } } } ResponseBuilder responseBuilder = Response.ok(); if (dataFile == null) { responseBuilder = Response.status(Status.BAD_REQUEST); responseBuilder.entity("Requests to store Datafiles must include a DataFileDescriptor."); } else { try { dataFile = dao.storeDataFile(dataFile, is); } finally { IOUtils.closeQuietly(is); } DataFileDescriptor result = DataFileServiceUtil.dataFileToDescriptor(dataFile); responseBuilder.entity(result); } // cache control // CacheControl cc = new CacheControl(); // cc.setMaxAge(60 * 10);// ten minutes // cc.setMustRevalidate(false); // responseBuilder.cacheControl(cc); // eTag logic // EntityTag eTag = new EntityTag(offeringId, true); // responseBuilder.tag(eTag); responseBuilder.cacheControl(ResponseUtil.getNoStoreCacheControl()); return responseBuilder.build(); } private DataFile descriptorToDataFile(DataFileDao dao, DataFileDescriptor dfd) { DataFile dataFile; if (dfd.getId() != null && dfd.getId() != 0) { dataFile = dao.findById(dfd.getId()); dataFile.setComments(dfd.getComments()); dataFile.setPath(dfd.getName()); dataFile.setCreator(dfd.getCreator()); } else { dataFile = DataFileServiceUtil.descriptorToDataFile(dfd); } return dataFile; } /** * @{inheritDoc */ @Override public Response deleteDataFile(Integer id) { ResponseBuilder responseBuilder = Response.ok(); DataFileDao dao = new DataFileDao(); dao.delete(id); responseBuilder.cacheControl(ResponseUtil.getNoStoreCacheControl()); return responseBuilder.build(); } /** * @{inheritDoc */ @Override public Response getDataFiles() { ResponseBuilder responseBuilder = Response.ok(); DataFileDao dao = new DataFileDao(); List<DataFile> all = dao.findAll(); List<DataFileDescriptor> result = new ArrayList<DataFileDescriptor>(); for (DataFile df : all) { result.add(DataFileServiceUtil.dataFileToDescriptor(df)); } responseBuilder.entity(new DataFileDescriptorContainer(result)); responseBuilder.cacheControl(ResponseUtil.getNoStoreCacheControl()); return responseBuilder.build(); } /** * @{inheritDoc */ @Override public Response getDataFile(Integer id) { ResponseBuilder responseBuilder = Response.ok(); DataFileDao dao = new DataFileDao(); DataFile df = dao.findById(id); if (df != null) { responseBuilder.entity(DataFileServiceUtil.dataFileToDescriptor(df)); } responseBuilder.cacheControl(ResponseUtil.getNoStoreCacheControl()); return responseBuilder.build(); } /** * @{inheritDoc */ @Override public Response setDataFile(Integer id, FormDataMultiPart formData) { return saveOrUpdateDataFile(formData); } /** * @param offset * @param numLines * @param dataFile * @return */ private StreamingOutput getStreamingOutput(final int offset, final int numLines, DataFile dataFile) { final FileStorage fileStorage = FileStorageFactory.getFileStorage(new TankConfig().getDataFileStorageDir(), false); final FileData fd = DataFileUtil.getFileData(dataFile); return new StreamingOutput() { public void write(OutputStream outputStream) { BufferedReader in = null; // Get the object of DataInputStream PrintWriter out = null; try { int nl = numLines; in = new BufferedReader(new InputStreamReader(fileStorage.readFileData(fd), "utf-8")); out = new PrintWriter(outputStream); if (!fd.getFileName().toLowerCase().endsWith(".csv")) { nl = -1; } // Read File Line By Line String strLine; int lineNum = 0; int os = offset < 0 ? 0 : offset; while ((strLine = in.readLine()) != null && (nl < 0 || lineNum < (os + numLines))) { if (numLines < 0 || lineNum >= os) { out.println(strLine); } lineNum++; } } catch (IOException e) { LOG.error("Error streaming file: " + e.toString(), e); throw new WebApplicationException(e, Response.Status.INTERNAL_SERVER_ERROR); } finally { IOUtils.closeQuietly(out); IOUtils.closeQuietly(in); } } }; } /** * @{inheritDoc */ @Override public Response downloadDataFileData(Integer id) { ResponseBuilder responseBuilder = Response.ok(); DataFileDao dataFileDao = new DataFileDao(); DataFile dataFile = dataFileDao.findById(id); StreamingOutput streamingOutput = getStreamingOutput(0, -1, dataFile); String filename = dataFile.getPath(); responseBuilder.header("Content-Disposition", "attachment; filename=\"" + filename + "\""); responseBuilder.entity(streamingOutput); return responseBuilder.build(); } }