FileBackedOutputStream on Appengine - java

My application on Appengine create a csv file with more 65535 rows
But, I have an error of type OutOfMemoryError when writing :
java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:2271)
at java.io.ByteArrayOutputStream.grow(ByteArrayOutputStream.java:118)
at java.io.ByteArrayOutputStream.ensureCapacity(ByteArrayOutputStream.java:93)
at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:153)
White this code :
public static byte[] joinLines(Collection<String> lines) {
final ByteArrayOutputStream stream = new ByteArrayOutputStream();
boolean firstElement = true;
for (final String part : lines) {
String value = part + LINE_SEPARATOR;
if (firstElement) {
value = addExcelPrefix(value);
firstElement = false;
}
final int currentSize = value.length();
try {
stream.write(value.getBytes(ENCODING), 0, currentSize); // OutOfMemoryError HERE
} catch (UnsupportedEncodingException e) {
LOGGER.info(e.getMessage());
}
}
return stream.toByteArray();
}
So I used FileBackedOutputStream of Guava for solve the problem of OutOfMemoryError :
public static byte[] joinLines(Collection<String> lines) throws IOException {
final FileBackedOutputStream stream = new FileBackedOutputStream(THRESHOLD, true);
boolean firstElement = true;
for (final String part : lines) {
String value = part + LINE_SEPARATOR;
if (firstElement) {
value = addExcelPrefix(value);
firstElement = false;
}
final int currentSize = value.length();
try {
stream.write(value.getBytes(ENCODING), 0, currentSize);
} catch (IOException e) {
LOGGER.error(e.getMessage());
}
}
return stream.asByteSource().read();
}
But, on appengine, I now an error of type SecurityException when creating of temporary file :
java.lang.SecurityException: Unable to create temporary file
at java.io.File.checkAndCreate(File.java:2083)
at java.io.File.createTempFile(File.java:2198)
at java.io.File.createTempFile(File.java:2244)
at com.google.common.io.FileBackedOutputStream.update(FileBackedOutputStream.java:196)
at com.google.common.io.FileBackedOutputStream.write(FileBackedOutputStream.java:178)
How to allow create temporary file on Appengine with FileBackedOutputStream ?
In a bucket, how ?
Thanks

I used GcsService that solves my problem :
protected String uploadBytesForCsv(Map<Integer, Map<Integer, Object>> rows) throws IOException {
LOGGER.info("Get Bytes For Csv");
final Collection<String> lines = cellsToCsv(rows);
LOGGER.info("number line : " + lines.size());
boolean firstElement = true;
final String fileName = getFileName();
final GcsFilename gcsFilename = new GcsFilename(config.getBucketName(), fileName);
final GcsService gcsService = GcsServiceFactory.createGcsService();
final GcsOutputChannel outputChannel = gcsService.createOrReplace(gcsFilename, GcsFileOptions.getDefaultInstance());
for (final String part : lines) {
final ByteArrayOutputStream stream = new ByteArrayOutputStream();
String value = part + LINE_SEPARATOR;
if (firstElement) {
value = addExcelPrefix(value);
firstElement = false;
}
final int currentSize = value.length();
try {
stream.write(value.getBytes(ENCODING), 0, currentSize);
outputChannel.write(ByteBuffer.wrap(stream.toByteArray()));
} catch (UnsupportedEncodingException e) {
LOGGER.info(e.getMessage());
}
stream.flush();
stream.close();
}
outputChannel.close();
return new UrlBuilder(config.getStorageUrlForExport())
.setBucketName(config.getBucketName())
.setFilename(fileName).build();
}

Related

Android - Zip Path Traversal in play store

I am uploading my App on play store but get me bellow error:
Zip Path Traversal Your app contains an unsafe unzipping pattern that
may lead to a Path Traversal vulnerability. Please see this Google
Help Center article to learn how to fix the issue.
org.apache.cordova.Zip.unzipSync
I edited my source code like this LINK, but get me error.
Here is my source code changed:
public class Zip extends CordovaPlugin {
private static final String LOG_TAG = "Zip";
// Can't use DataInputStream because it has the wrong endian-ness.
private static int readInt(InputStream is) throws IOException {
int a = is.read();
int b = is.read();
int c = is.read();
int d = is.read();
return a | b << 8 | c << 16 | d << 24;
}
#Override
public boolean execute(String action, CordovaArgs args, final CallbackContext callbackContext) throws JSONException {
if ("unzip".equals(action)) {
unzip(args, callbackContext);
return true;
}
return false;
}
private void unzip(final CordovaArgs args, final CallbackContext callbackContext) {
this.cordova.getThreadPool().execute(new Runnable() {
public void run() {
unzipSync(args, callbackContext);
}
});
}
private void unzipSync(CordovaArgs args, CallbackContext callbackContext) {
InputStream inputStream = null;
try {
String zipFileName = args.getString(0);
String outputDirectory = args.getString(1);
// Since Cordova 3.3.0 and release of File plugins, files are accessed via cdvfile://
// Accept a path or a URI for the source zip.
Uri zipUri = getUriForArg(zipFileName);
Uri outputUri = getUriForArg(outputDirectory);
CordovaResourceApi resourceApi = webView.getResourceApi();
File tempFile = resourceApi.mapUriToFile(zipUri);
if (tempFile == null || !tempFile.exists()) {
String errorMessage = "Zip file does not exist";
callbackContext.error(errorMessage);
Log.e(LOG_TAG, errorMessage);
return;
}
File outputDir = resourceApi.mapUriToFile(outputUri);
outputDirectory = outputDir.getAbsolutePath();
outputDirectory += outputDirectory.endsWith(File.separator) ? "" : File.separator;
if (outputDir == null || (!outputDir.exists() && !outputDir.mkdirs())) {
String errorMessage = "Could not create output directory";
callbackContext.error(errorMessage);
Log.e(LOG_TAG, errorMessage);
return;
}
OpenForReadResult zipFile = resourceApi.openForRead(zipUri);
ProgressEvent progress = new ProgressEvent();
progress.setTotal(zipFile.length);
inputStream = new BufferedInputStream(zipFile.inputStream);
inputStream.mark(10);
int magic = readInt(inputStream);
if (magic != 875721283) { // CRX identifier
inputStream.reset();
} else {
// CRX files contain a header. This header consists of:
// * 4 bytes of magic number
// * 4 bytes of CRX format version,
// * 4 bytes of public key length
// * 4 bytes of signature length
// * the public key
// * the signature
// and then the ordinary zip data follows. We skip over the header before creating the ZipInputStream.
readInt(inputStream); // version == 2.
int pubkeyLength = readInt(inputStream);
int signatureLength = readInt(inputStream);
inputStream.skip(pubkeyLength + signatureLength);
progress.setLoaded(16 + pubkeyLength + signatureLength);
}
// The inputstream is now pointing at the start of the actual zip file content.
ZipInputStream zis = new ZipInputStream(inputStream);
inputStream = zis;
ZipEntry ze;
byte[] buffer = new byte[32 * 1024];
boolean anyEntries = false;
while ((ze = zis.getNextEntry()) != null) {
try {
anyEntries = true;
String compressedName = ze.getName();
if (ze.isDirectory()) {
try {
File dir = new File(outputDirectory + compressedName);
File f = new File(dir, ze.getName());
String canonicalPath = f.getCanonicalPath();
if (!canonicalPath.startsWith(dir.toString())){
dir.mkdirs();
}else {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
}
}
}
} catch (Exception e) {
String errorMessage = "An error occurred while unzipping.";
callbackContext.error(errorMessage);
Log.e(LOG_TAG, errorMessage, e);
}
} else {
File file = new File(outputDirectory + compressedName);
File f = new File(file, ze.getName());
String canonicalPath = f.getCanonicalPath();
if (!canonicalPath.startsWith(file.toString())) {
file.getParentFile().mkdirs();
if (file.exists() || file.createNewFile()) {
try {
Log.w("Zip", "extracting: " + file.getPath());
FileOutputStream fout = new FileOutputStream(file);
int count;
while ((count = zis.read(buffer)) != -1) {
fout.write(buffer, 0, count);
}
fout.close();
} catch (Exception e) {
String errorMessage = "An error occurred while unzipping.";
callbackContext.error(errorMessage);
Log.e(LOG_TAG, errorMessage, e);
}
}
}else {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
}
}
}
}
progress.addLoaded(ze.getCompressedSize());
updateProgress(callbackContext, progress);
zis.closeEntry();
} catch (Exception e) {
String errorMessage = "An error occurred while unzipping.";
callbackContext.error(errorMessage);
Log.e(LOG_TAG, errorMessage, e);
}
}
// final progress = 100%
progress.setLoaded(progress.getTotal());
updateProgress(callbackContext, progress);
if (anyEntries)
callbackContext.success();
else
callbackContext.error("Bad zip file");
} catch (Exception e) {
String errorMessage = "An error occurred while unzipping.";
callbackContext.error(errorMessage);
Log.e(LOG_TAG, errorMessage, e);
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
}
}
}
}
private void updateProgress(CallbackContext callbackContext, ProgressEvent progress) throws JSONException {
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, progress.toJSONObject());
pluginResult.setKeepCallback(true);
callbackContext.sendPluginResult(pluginResult);
}
private Uri getUriForArg(String arg) {
CordovaResourceApi resourceApi = webView.getResourceApi();
Uri tmpTarget = Uri.parse(arg);
return resourceApi.remapUri(
tmpTarget.getScheme() != null ? tmpTarget : Uri.fromFile(new File(arg)));
}
private static class ProgressEvent {
private long loaded;
private long total;
public long getLoaded() {
return loaded;
}
public void setLoaded(long loaded) {
this.loaded = loaded;
}
public void addLoaded(long add) {
this.loaded += add;
}
public long getTotal() {
return total;
}
public void setTotal(long total) {
this.total = total;
}
public JSONObject toJSONObject() throws JSONException {
return new JSONObject(
"{loaded:" + loaded +
",total:" + total + "}");
}
}
}

Invalid header signature when read any xls file

When I try to read xls file using the code below, I always get error:
org.apache.poi.poifs.filesystem.NotOLE2FileException: Invalid header signature; read 0x65572D2D2D2D2D2D, expected 0xE11AB1A1E011CFD0 - Your file appears not to be a valid OLE2 document.
This is my code:
public Result<List<IDto>> ReadExcelClassInfo2003(File file,
Timestamp createTime, Timestamp updateTime, BigDecimal createBy,
BigDecimal updateBy) {
Result<List<IDto>> resultData = new Result<List<IDto>>();
Integer numInsertSuccess = 0;
if (file == null) {
resultData.setErrorCode(ErrorCode.ERROR_FORMAT);
return resultData;
}
try {
InputStream is = new FileInputStream(file);
POIFSFileSystem fs = new POIFSFileSystem(is);
Integer classType = ClassTypeEnum.CLASSROOM.getValue();
Integer maxCol = ExcelConstant.MAX_COLUMN_CLASSROOM_INFO;
workbook = new HSSFWorkbook(fs);
HSSFSheet sheetClassInfo = workbook
.getSheetAt(0);
if (sheetClassInfo == null) {
resultData.setErrorCode(ErrorCode.ERROR_FORMAT);
return resultData;
}
//Some code to get data from excel file here.
is.close();
workbook.close();
} catch (FileNotFoundException e) {
resultData.setErrorCode(ErrorCode.ERROR_FORMAT);
return resultData;
} catch (IOException e) {
resultData.setErrorCode(ErrorCode.ERROR_FORMAT);
return resultData;
} catch (Exception e) {
resultData.setErrorCode(ErrorCode.ERROR_FORMAT);
return resultData;
}
if (numInsertSuccess == 0) {
resultData.setErrorCode(ErrorCode.CLASS_DATA_INVALID);
return resultData;
}
resultData.setErrorCode(ErrorCode.IMPORT_SUCCESS);
resultData.setMessage(numInsertSuccess.toString());
return resultData;
}
My controller code :
#POST
#Path("class/import")
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces(MediaType.APPLICATION_JSON)
#RolesAllowed(Role.TRAINING_ADMIN)
// public Response importClass(#FormParam("file") File file) {
public Response importClass(#Multipart("file") File file) {
LOGGER.info("Received PUT import class: file=" + file.length());
if (checkTokenAndRole(new int[] {1, 11}).getStatus() != Response.Status.OK.getStatusCode()) {
return LoginError(checkToken().getStatus());
} else {
String token = request.getHeader(HttpHeaders.AUTHORIZATION);
String fileExtension = request.getHeader("FileExtension");
return ClassService.getInstance().importClass(file, fileExtension,
token);
}
}
And the method are call by controller :
public Response importClass(File file, String fileExtension, String token) {
Result<List<IDto>> result = new Result<List<IDto>>();
try {
ErrorDTO errorDto = new ErrorDTO();
String data = "";
double bytes = file.length();
double kilobytes = (bytes / 1024);
double megabytes = (kilobytes / 1024);
if (megabytes > ExcelConstant.MAX_FILE_SIZE) {
errorDto.setErrorCode(ErrorCode.ERROR_FORMAT);
data = Utility.toJSONString(errorDto);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(data).build();
}
Timestamp createTime = new Timestamp(System.currentTimeMillis());
Timestamp updateTime = new Timestamp(System.currentTimeMillis());
BigDecimal createBy = null;
BigDecimal updateBy = null;
Result<UserInfoDTO> userInfo = DaoManager.getUserInfoDao()
.getUserInfoByToken(token);
if (userInfo.getData() != null) {
createBy = userInfo.getData().getId();
updateBy = userInfo.getData().getId();
}
result = DaoManager.getClassDao().importClass(file, fileExtension,
createTime, updateTime, createBy, updateBy);
int errorCode = result.getErrorCode();
String message = result.getMessage();
errorDto = new ErrorDTO();
errorDto.setErrorCode(errorCode);
errorDto.setMessage(message);
data = Utility.toJSONString(errorDto);
// release memory
userInfo = null;
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(data).build();
} catch (Exception e) {
e.printStackTrace();
LOGGER.error(e.getMessage());
result.setStatus(Constant.INTERNAL_SERVER_ERROR);
result.setErrorCode(ErrorCode.IMPORT_ERROR);
return super.responseData(result);
}
}
public Result<List<IDto>> importClass(File file, String fileExtension,
Timestamp createTime, Timestamp updateTime, BigDecimal createBy,
BigDecimal updateBy) throws IOException {
return ExportExcelService.getInstance().ReadExcelClassInfo2003(file,
fileExtension, createTime, updateTime, createBy, updateBy);
}
I debuged and found the process always check new POIFSFileSystem and throw exception with error above. I tested with all xls file I have and have same error.
Any can help me resolve this problem, and what the header 0x65572D2D2D2D2D2D ?
Thanks.

Flatbuffer writing in binary file in android give only single response

I am new at flatbuffer. I had created a schema file from outside the project and adding the user(Monster as in Flatbuffer document) inside the binary via java code in android. everything works fine. but the time of reading binary file data it only gives me the user length 1. I had added 3 people but it's give me the length of monsters is 1 at the time of reading. can anyone help to figure this out. Here is the code->
this is the full code ->
enter code here
builder = new FlatBufferBuilder(1024);
public void addNewData(String emailOffset, String nameOffset,String
contactNoOffset, String DOJOffset, String departmentOffset,
String empIdOffset, float[] embeddingOffset)
{
int storeembedd = SingleJson.createEmbeddingVector(builder,
embeddingOffset);
int hereEmailOffset = builder.createString(emailOffset);
int hereNameOffset = builder.createString(nameOffset);
int hereContactOffset = builder.createString(contactNoOffset);
int hereDOJOffset = builder.createString(DOJOffset);
int hereDepartmentOffset=builder.createString(departmentOffset);
int hereImpIdOffset = builder.createString(empIdOffset);
int test = SingleJson.createSingleJson(builder, hereEmailOffset,
hereNameOffset, hereContactOffset
, hereDOJOffset, hereDepartmentOffset, hereImpIdOffset,
storeembedd);
int [] offsetOfMonster = new int[1];
offsetOfMonster[0] = test;
int temp = Monsters.createMonstersVector(builder,
offsetOfMonster);
Monsters.startMonsters(builder);
Monsters.addMonsters(builder, temp);
int orc = Monsters.endMonsters(builder);
builder.finish(orc);
byte[] buf1 = builder.sizedByteArray();
openAndAppenedInBinary(buf1);
}
private void openAndAppenedInBinary(byte[] buf1) {
FileOutputStream output = null;
try {
InputStream inputStream = new FileInputStream(newFile());
byte[] buffer = new byte[inputStream.available()];
if (inputStream.available() == 0) {
output = new FileOutputStream(newFile(), true);
output.write(buf1);
} else {
while (inputStream.read(buffer) != -1) {
output = new FileOutputStream(newFile(), true);
output.write(buffer);
output.write(buf1);
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private String newFile() {
File file = new File(Environment.getExternalStorageDirectory()
+ "/Android/data/"
+ context.getPackageName()
+ "/binFile");
if (!file.exists()) {
if (!file.mkdir()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
try {
Path dir = Paths.get(file.getAbsolutePath());
Files.createDirectory(dir);
} catch (IOException e) {
Path parentDir = Paths.get(file.getParent());
if (!Files.exists(parentDir)) {
try {
Files.createDirectories(parentDir);
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
}
}
File binFile = new File(file, "renamed.bin");
try {
FileWriter writer = new FileWriter(binFile);
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
return binFile.getAbsolutePath();
}
here is my reading code of flatbiffer->
new FlatParsingForPerticularId().execute(readRawResource(R.raw.renamed));//renamed is my bin file
private class FlatParsingForPerticularId extends AsyncTask {
#Override
protected String doInBackground(Object... params) {
byte[] buffer = (byte[]) params[0];
long startTime = System.currentTimeMillis();
ByteBuffer bb = ByteBuffer.wrap(buffer);
Monsters monsterList = Monsters.getRootAsMonsters(bb);
int length = monsterList.monstersLength();
SingleJson monster = null;
for (int i = 0; i < length; i++) {//here I m getting length 1 intead of 3
monster = monsterList.monsters(i);
if (i == outputval[0]) {
outputval[0] = (int) monster.EmpNo();
break;
}
}
long endTime = System.currentTimeMillis() - startTime;
String textToShow = "Elements: " + monsterList.monstersLength() + ": load time: " + endTime + "ms";
String[] monsterArr = monster.Name().split(" ");
return monsterArr[0];
}

How to build a zip file with a size of 400 GB in java

I need to download all the documents from an alfresco site that contains 400GB of documents.
The code below is ok for create a small zip file (about 1GB) otherwise it takes too much memory.
I would not like to keep ZipOutputStream in memory, i would like to use memory only for every document copied to the Zip file or use a temporary file that is overwritten for each document.
What is the best practice for this kind of problem?
This piece of code is called from my main:
FolderImpl sitoFolder = (FolderImpl) cmisObject;
List<Tree<FileableCmisObject>> sitoFolderDescendants = sitoFolder.getDescendants(-1);
byte[] zipFile = createZipFILE(sitoFolderDescendants);
String rootPath = cartella_download_file;
File dir = new File(rootPath + File.separator);
if (!dir.exists()) {
dir.mkdirs();
}
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String stringDate = sdf.format(date);
String nameZipFile = sitoFolder.getName().replaceAll("\\s","");
File serverFile = new File(dir.getAbsolutePath() + File.separator + stringDate+"_"+nameZipFile+".zip");
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(serverFile));
IOUtils.write(zipFile, bufferedOutputStream);
bufferedOutputStream.close();
//Returns the zip file
private byte[] createZipFILE(List<Tree<FileableCmisObject>> list) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ByteTransform byteTransform = new ByteTransform();
try {
ReportDocument reportDocument = new ReportDocument();
ZipOutputStream zos = new ZipOutputStream(baos);
for (Tree<FileableCmisObject> aList : list) {
traverseTree(aList, zos, reportDocument);
}
zos.close();
return baos.toByteArray();
} catch (IOException exc) {
reportLog.error(exc.getMessage());
} finally {
baos.close();
}
return new byte[0];
}
private void traverseTree(Tree<FileableCmisObject> tree, ZipOutputStream zos, ReportDocument reportDocument) {
for (int i=0; i<tree.getChildren().size(); i++) {
Tree<FileableCmisObject> child = tree.getChildren().get(i);
if (CmisUtil.isDocument(child.getItem())) {
Document document = (Document) child.getItem();
try {
addToZipFile(document, zos);
} catch (IOException ioExc) {
appLog.error(ioExc.getMessage());
}
} else if(CmisUtil.isFolder(child.getItem())) {
Folder folder = (Folder) child.getItem();
if (folder.getChildren().getTotalNumItems() == 0) {
try {
addToZipFolder(folder, zos);
} catch (IOException ioExc) {
appLog.error(ioExc.getMessage());
}
}
}
traverseTree(child, zos, reportDocument);
}
}
//Service method to add documents to the zip file
private void addToZipFile(Document document, ZipOutputStream zos) throws IOException {
InputStream inputStream = document.getContentStream().getStream();
String path = document.getPaths().get(0).replace(sito_export_path, "");
ZipEntry zipEntry = new ZipEntry(path);
zos.putNextEntry(zipEntry);
IOUtils.copy(inputStream, zos, 1024);
inputStream.close();
zos.closeEntry();
}
//Service method to add empty folder to the zip file
private void addToZipFolder(Folder folder, ZipOutputStream zos) throws IOException {
String path = folder.getPaths().get(0).replace(sito_export_path, "");
ZipEntry zipEntry = new ZipEntry(path.concat("/"));
zos.putNextEntry(zipEntry);
}
I solved it. I first created a directory on the server and then created the zip file on this directory directly.
The error was to save all the files first on: ByteArrayOutputStream and then on the zip file.
File serverFile = new File(dir.getAbsolutePath() + File.separator + stringDate+"_"+nameZipFile+".zip");
FileOutputStream fileOutputStream = new FileOutputStream(serverFile);
ZipArchiveOutputStream zos = new ZipArchiveOutputStream(fileOutputStream);
for (Tree<FileableCmisObject> aList : sitoFolderDescendants) {
traverseTree(aList, zos, reportDocument);
}
zos.close();
In the finally block I close the FileOutputStream.
Than I changed the services method using: ZipArchiveOutputStream and ZipArchiveEntry.
private void addToZipFolder(Folder folder, ZipArchiveOutputStream zos) throws IOException {
String path = folder.getPaths().get(0).replace(sito_export_path, "");
ZipArchiveEntry zipEntry = new ZipArchiveEntry(path.concat("/"));
appLog.info("aggiungo cartella vuota "+folder.getName()+" al file zip");
zos.putArchiveEntry(zipEntry);
zos.closeArchiveEntry();
}
private void addToZipFile(Document document, ZipArchiveOutputStream zos) throws IOException {
InputStream inputStream = document.getContentStream().getStream();
String path = document.getPaths().get(0).replace(sito_export_path, "");
ZipArchiveEntry entry = new ZipArchiveEntry(path);
entry.setSize(document.getContentStreamLength());
zos.putArchiveEntry(entry);
byte buffer[] = new byte[1024];
while (true) {
int nRead = inputStream.read(buffer, 0, buffer.length);
if (nRead <= 0) {
break;
}
zos.write(buffer, 0, nRead);
}
inputStream.close();
zos.closeArchiveEntry();
}
Actually i have create downlod as zip functionality for alfresco 3.4.d version and used following code.i have not checked it for GB's file because i don't have that much data.it may be help to you.
This is Java Backed WebScript.
/*
* this class create a zip file base on given(parameter) node
* */
public class ZipContents extends AbstractWebScript {
private static Log logger = LogFactory.getLog(ZipContents.class);
private static final int BUFFER_SIZE = 1024;
private static final String MIMETYPE_ZIP = "application/zip";
private static final String TEMP_FILE_PREFIX = "alf";
private static final String ZIP_EXTENSION = ".zip";
private ContentService contentService;
private NodeService nodeService;
private NamespaceService namespaceService;
private DictionaryService dictionaryService;
private StoreRef storeRef;
private String encoding;
public void setNodeService(NodeService nodeService) {
this.nodeService = nodeService;
}
public void setContentService(ContentService contentService) {
this.contentService = contentService;
}
public void setNamespaceService(NamespaceService namespaceService) {
this.namespaceService = namespaceService;
}
public void setDictionaryService(DictionaryService dictionaryService) {
this.dictionaryService = dictionaryService;
}
public void setStoreUrl(String url) {
this.storeRef = new StoreRef(url);
}
public void setEncoding(String encoding) {
this.encoding = encoding;
}
public void execute(WebScriptRequest req, WebScriptResponse res) throws IOException {
String nodes = req.getParameter("nodes");
if (nodes == null || nodes.length() == 0) {
throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "nodes");
}
List<String> nodeIds = new ArrayList<String>();
StringTokenizer tokenizer = new StringTokenizer(nodes, ",");
if (tokenizer.hasMoreTokens()) {
while (tokenizer.hasMoreTokens()) {
nodeIds.add(tokenizer.nextToken());
}
}
String filename = req.getParameter("filename");
if (filename == null || filename.length() == 0) {
throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "filename");
}
String noaccentStr = req.getParameter("noaccent");
if (noaccentStr == null || noaccentStr.length() == 0) {
throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "noaccent");
}
try {
res.setContentType(MIMETYPE_ZIP);
res.setHeader("Content-Transfer-Encoding", "binary");
res.addHeader("Content-Disposition", "attachment;filename=\"" + unAccent(filename) + ZIP_EXTENSION + "\"");
res.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
res.setHeader("Pragma", "public");
res.setHeader("Expires", "0");
createZipFile(nodeIds, res.getOutputStream(), new Boolean(noaccentStr));
} catch (RuntimeException e) {
throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
}
}
public void createZipFile(List<String> nodeIds, OutputStream os, boolean noaccent) throws IOException {
File zip = null;
try {
if (nodeIds != null && !nodeIds.isEmpty()) {
zip = TempFileProvider.createTempFile(TEMP_FILE_PREFIX, ZIP_EXTENSION);
FileOutputStream stream = new FileOutputStream(zip);
CheckedOutputStream checksum = new CheckedOutputStream(stream, new Adler32());
BufferedOutputStream buff = new BufferedOutputStream(checksum);
ZipArchiveOutputStream out = new ZipArchiveOutputStream(buff);
out.setEncoding(encoding);
out.setMethod(ZipArchiveOutputStream.DEFLATED);
out.setLevel(Deflater.BEST_COMPRESSION);
if (logger.isDebugEnabled()) {
logger.debug("Using encoding '" + encoding + "' for zip file.");
}
try {
for (String nodeId : nodeIds) {
NodeRef node = new NodeRef(storeRef, nodeId);
addToZip(node, out, noaccent, "");
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
} finally {
out.close();
buff.close();
checksum.close();
stream.close();
if (nodeIds.size() > 0) {
InputStream in = new FileInputStream(zip);
try {
byte[] buffer = new byte[BUFFER_SIZE];
int len;
while ((len = in.read(buffer)) > 0) {
os.write(buffer, 0, len);
}
} finally {
IOUtils.closeQuietly(in);
}
}
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
} finally {
// try and delete the temporary file
if (zip != null) {
zip.delete();
}
}
}
public void addToZip(NodeRef node, ZipArchiveOutputStream out, boolean noaccent, String path) throws IOException {
QName nodeQnameType = this.nodeService.getType(node);
// Special case : links
if (this.dictionaryService.isSubClass(nodeQnameType, ApplicationModel.TYPE_FILELINK)) {
NodeRef linkDestinationNode = (NodeRef) nodeService.getProperty(node, ContentModel.PROP_LINK_DESTINATION);
if (linkDestinationNode == null) {
return;
}
// Duplicate entry: check if link is not in the same space of the
// link destination
if (nodeService.getPrimaryParent(node).getParentRef().equals(nodeService.getPrimaryParent(linkDestinationNode).getParentRef())) {
return;
}
nodeQnameType = this.nodeService.getType(linkDestinationNode);
node = linkDestinationNode;
}
String nodeName = (String) nodeService.getProperty(node, ContentModel.PROP_NAME);
nodeName = noaccent ? unAccent(nodeName) : nodeName;
if (this.dictionaryService.isSubClass(nodeQnameType, ContentModel.TYPE_CONTENT)) {
ContentReader reader = contentService.getReader(node, ContentModel.PROP_CONTENT);
if (reader != null) {
InputStream is = reader.getContentInputStream();
String filename = path.isEmpty() ? nodeName : path + '/' + nodeName;
ZipArchiveEntry entry = new ZipArchiveEntry(filename);
entry.setTime(((Date) nodeService.getProperty(node, ContentModel.PROP_MODIFIED)).getTime());
entry.setSize(reader.getSize());
out.putArchiveEntry(entry);
byte buffer[] = new byte[BUFFER_SIZE];
while (true) {
int nRead = is.read(buffer, 0, buffer.length);
if (nRead <= 0) {
break;
}
out.write(buffer, 0, nRead);
}
is.close();
out.closeArchiveEntry();
} else {
logger.warn("Could not read : " + nodeName + "content");
}
} else if (this.dictionaryService.isSubClass(nodeQnameType, ContentModel.TYPE_FOLDER)
&& !this.dictionaryService.isSubClass(nodeQnameType, ContentModel.TYPE_SYSTEM_FOLDER)) {
List<ChildAssociationRef> children = nodeService.getChildAssocs(node);
if (children.isEmpty()) {
String folderPath = path.isEmpty() ? nodeName + '/' : path + '/' + nodeName + '/';
ZipArchiveEntry entry = new ZipArchiveEntry(folderPath);
entry.setSize(0);
entry.setTime(((Date) nodeService.getProperty(node, ContentModel.PROP_MODIFIED)).getTime());
out.putArchiveEntry(entry);
out.closeArchiveEntry();
} else {
for (ChildAssociationRef childAssoc : children) {
NodeRef childNodeRef = childAssoc.getChildRef();
addToZip(childNodeRef, out, noaccent, path.isEmpty() ? nodeName : path + '/' + nodeName);
}
}
} else {
logger.info("Unmanaged type: " + nodeQnameType.getPrefixedQName(this.namespaceService) + ", filename: " + nodeName);
}
}
/**
* ZipEntry() does not convert filenames from Unicode to platform (waiting
* Java 7) http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4244499
*
* #param s
* #return
*/
public static String unAccent(String s) {
String temp = Normalizer.normalize(s, Normalizer.NFD, 0);
return temp.replaceAll("[^\\p{ASCII}]", "");
}
}

How to get stream output as string?

In my servlet I am running a few command line commands in background, I've successfully printed output on console.
My doGet()
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
String[] command =
{
"zsh"
};
Process p = Runtime.getRuntime().exec(command);
new Thread(new SyncPipe(p.getErrorStream(), response.getOutputStream())).start();
new Thread(new SyncPipe(p.getInputStream(), response.getOutputStream())).start();
PrintWriter stdin = new PrintWriter(p.getOutputStream());
stdin.println("source ./taxenv/bin/activate");
stdin.println("python runner.py");
stdin.close();
int returnCode = 0;
try {
returnCode = p.waitFor();
}
catch (InterruptedException e) {
e.printStackTrace();
} System.out.println("Return code = " + returnCode);
}
class SyncPipe implements Runnable
{
public SyncPipe(InputStream istrm, OutputStream ostrm) {
istrm_ = istrm;
ostrm_ = ostrm;
}
public void run() {
try
{
final byte[] buffer = new byte[1024];
for (#SuppressWarnings("unused")
int length = 0; (length = istrm_.read(buffer)) != -1; )
{
// ostrm_.write(buffer, 0, length);
((PrintStream) ostrm_).println();
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
private final OutputStream ostrm_;
private final InputStream istrm_;
}
Now, I want to save the ostrm_ to a string or list, and use that inside doGet()
How to achieve this?
==============================EDIT============================
Based on answers below, I've edited my code as follows
int length = 0; (length = istrm_.read(buffer)) != -1; )
{
// ostrm_.write(buffer, 0, length);
String str = IOUtils.toString(istrm_, "UTF-8");
//((PrintStream) ostrm_).println();
System.out.println(str);
}
Now, How do I get the str in runnable class into my doGet()?
You can use Apache Commons IO.
Here is the documentation of IOUtils.toString() from their javadocs
Gets the contents of an InputStream as a String using the specified character encoding. This
method buffers the input internally, so there is no need to use a
BufferedInputStream.
Parameters: input - the InputStream to read from encoding - the
encoding to use, null means platform default Returns: the requested
String Throws: NullPointerException - if the input is null IOException
- if an I/O error occurs
Example Usage:
String str = IOUtils.toString(yourInputStream, "UTF-8");
You can call something like the following:
(EDIT: added also the client calls)
public void run() {
try
{
String out = getAsString(istrm_);
((PrintStream) ostrm_).println(out);
} catch (Exception e) {
e.printStackTrace();
}
}
public static String getAsString(InputStream is) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int cur = -1;
while((cur = is.read()) != -1 ){
baos.write(cur);
}
return getAsString(baos.toByteArray());
}
public static String getAsString(byte[] arr) throws Exception {
String res = "";
for(byte b : arr){
res+=(char)b;
}
return res;
}

Categories

Resources