I am trying to save a file by using google drive api.
Code that I am using to save file at the moment looks following:
final java.io.File file = new java.io.File(Environment.getExternalStorageDirectory() + java.io.File.separator + "Json.txt");
try {
file.createNewFile();
if (file.exists()) {
final FileWriter fileWriter = new FileWriter(file);
final String json = gson.toJson(filesEvent);
fileWriter.write(json);
fileWriter.close();
}
} catch (IOException e) {
e.printStackTrace();
}
This is the part that is supposed to get the file contents:
final StringBuilder sb = getStringBuilder(new FileReader(Environment.getExternalStorageDirectory() + java.io.File.separator + "Json.txt"));
File file = gson.fromJson(sb.toString(), File.class);
I assume, you want to save a text file ('json.txt') to Google Drive and your code applies to Android.
First, you do not indicate what API you decided to use, the REST Api or the GDAA.
Starting with java.io.File as an input (your first code block), here are code snippets for both the GDAA and REST Apis.
GDAA: (you may consider turning the 'await' methods into callbacks, or you have to wrap it in non-UI thread)
dependencies {
...
compile 'com.google.android.gms:play-services:7.8.0'
}
com.google.android.gms.common.api.GoogleApiClient mGAC;
...
/**********************************************************************
* create file/folder in GOODrive
* #param prnId parent's ID, (null for root)
* #param titl file name
* #param mime file mime type
* #param file file (with content) to create
* #return file id / null on fail
*/
DriveId createFile(DriveId prnId, String titl, String mime, File file) {
DriveId dId = null;
if (mGAC != null && mGAC.isConnected() && titl != null && mime != null && file != null) {
DriveFolder pFldr = (prnId == null) ?
Drive.DriveApi.getRootFolder(mGAC): Drive.DriveApi.getFolder(mGAC, prnId);
if (pFldr == null) return null; //----------------->>>
MetadataChangeSet meta;
DriveContentsResult r1 = Drive.DriveApi.newDriveContents(mGAC).await();
if (r1 == null || !r1.getStatus().isSuccess()) return null; //-------->>>
meta = new Builder().setTitle(titl).setMimeType(mime).build();
DriveFileResult r2 = pFldr.createFile(mGAC, meta, r1.getDriveContents()).await();
DriveFile dFil = r2 != null && r2.getStatus().isSuccess() ? r2.getDriveFile() : null;
if (dFil == null) return null; //---------->>>
r1 = dFil.open(mGAC, DriveFile.MODE_WRITE_ONLY, null).await();
if ((r1 != null) && (r1.getStatus().isSuccess())) {
Status stts = fileToCont(r1.getDriveContents(), file).commit(mGAC, meta).await();
if ((stts != null) && stts.isSuccess()) {
MetadataResult r3 = dFil.getMetadata(mGAC).await();
if (r3 != null && r3.getStatus().isSuccess()) {
dId = r3.getMetadata().getDriveId();
}
}
}
}
return dId;
}
DriveContents fileToCont(DriveContents driveContents, File file) {
OutputStream oos = driveContents.getOutputStream();
if (oos != null) try {
InputStream is = new FileInputStream(file);
byte[] buf = new byte[4096];
int c;
while ((c = is.read(buf, 0, buf.length)) > 0) {
oos.write(buf, 0, c);
oos.flush();
}
} catch (Exception e) { UT.le(e);}
finally {
try {
oos.close();
} catch (Exception ignore) {
}
}
return driveContents;
}
REST Api: (you have to wrap it in non-UI thread)
dependencies {
...
compile 'com.google.apis:google-api-services-drive:v2-rev105-1.17.0-rc'
compile 'com.google.api-client:google-api-client-android:1.20.0'
compile 'com.google.http-client:google-http-client-gson:1.20.0'
}
com.google.api.services.drive.Drive mGOOSvc;
...
/***************************************************************
* create file/folder in GOODrive
* #param prnId parent's ID, (null or "root") for root
* #param titl file name
* #param mime file mime type
* #param file file (with content) to create
* #return file id / null on fail
*/
static String createFile(String prnId, String titl, String mime, java.io.File file) {
String rsId = null;
if (mGOOSvc != null && titl != null && mime != null && file != null) try {
File meta = new File();
meta.setParents(Arrays.asList(new ParentReference().setId(prnId == null ? "root" : prnId)));
meta.setTitle(titl);
meta.setMimeType(mime);
File gFl = mGOOSvc.files().insert(meta, new FileContent(mime, file)).execute();
if (gFl != null)
rsId = gFl.getId();
}
catch (UserRecoverableAuthIOException uraIOEx) {
// handle uraIOEx;
}
catch (IOException e) {
if (e instanceof GoogleJsonResponseException) {
if (404 == ((GoogleJsonResponseException)e).getStatusCode())
// handle error;
}
} catch (Exception e) {
// handle error;
}
return rsId;
}
Wider context of these methods can be found here and here if you care to dig deeper.
Good Luck
Related
I am trying to count the number of attachments on a PDF to verify our attachment code. The code I have works most of the time but recently it started failing when the number of attachments went up as well as the size of the attachments. Example: I have a PDF with 700 attachments which total 1.6 gb. And another with 65 attachments of around 10mb. The 65 count was done incrementally. We had built it up file by file. At 64 files (about 9.8mb) the routine counted fine. Add file 65 (about .5mb) and the routine failed.
This is on itextpdf-5.5.9.jar under jre1.8.0_162
We are still testing different combinations of file numbers and size to see where it breaks.
private static String CountFiles() throws IOException, DocumentException {
Boolean errorFound = new Boolean(true);
PdfDictionary root;
PdfDictionary names;
PdfDictionary embeddedFiles;
PdfReader reader = null;
String theResult = "unknown";
try {
if (!theBaseFile.toLowerCase().endsWith(".pdf"))
theResult = "file not PDF";
else {
reader = new PdfReader(theBaseFile);
root = reader.getCatalog();
names = root.getAsDict(PdfName.NAMES);
if (names == null)
theResult = "0";
else {
embeddedFiles = names.getAsDict(PdfName.EMBEDDEDFILES);
PdfArray namesArray = embeddedFiles.getAsArray(PdfName.NAMES);
theResult = String.format("%d", namesArray.size() / 2);
}
reader.close();
errorFound = false;
}
}
catch (Exception e) {
theResult = "unknown";
}
finally {
if (reader != null)
reader.close();
}
if (errorFound)
sendError(theResult);
return theResult;
}
private static String AttachFileInDir() throws IOException, DocumentException {
String theResult = "unknown";
String outputFile = theBaseFile.replaceFirst("(?i).pdf$", ".attach.pdf");
int maxFiles = 1000;
int fileCount = 1;
PdfReader reader = null;
PdfStamper stamper = null;
try {
if (!theBaseFile.toLowerCase().endsWith(".pdf"))
theResult = "basefile not PDF";
else if (theFileDir.length() == 0)
theResult = "no attach directory";
else if (!Files.isDirectory(Paths.get(theFileDir)))
theResult = "invalid attach directory";
else {
reader = new PdfReader(theBaseFile);
stamper = new PdfStamper(reader, new FileOutputStream(outputFile));
stamper.getWriter().setPdfVersion(PdfWriter.VERSION_1_7);
Path dir = FileSystems.getDefault().getPath(theFileDir);
DirectoryStream<Path> stream = Files.newDirectoryStream(dir);
for (Path path : stream) {
stamper.addFileAttachment(null, null, path.toFile().toString(), path.toFile().getName());
if (++fileCount > maxFiles) {
theResult = "maxfiles exceeded";
break;
}
}
stream.close();
stamper.close();
reader.close();
theResult = "SUCCESS";
}
}
catch (Exception e) {
theResult = "unknown";
}
finally {
if (stamper != null)
stamper.close();
if (reader != null)
reader.close();
}
if (theResult != "SUCCESS")
sendError(theResult);
return theResult;
}
I expect a simple count of attachments back. What seems to be happening is the namesArray is coming back null. The result stays "unknown". I suspect the namesArray is trying to hold all the files and choking on the size.
Note: The files are being attached using the AttachFileInDir procedure. Dump all the files in a directory and run the AttachFileInDir. And yes the error trapping in AttachFileInDir needs work.
Any help would be appreciated or another method welcome
I finally got it. Turns out each KID is a dictionary of NAMES….
Each NAMES hold 64 file references. At 65 files and up it made a KIDS dictionary array of names. So 279 files = ( 8*64 +46 )/2 (9 total KIDS array elements).
One thing that I had to compensate for. If one deletes all the attachments off a pdf it leaves artifacts behind as opposed to a PDF that never had an attachment
private static String CountFiles() throws IOException, DocumentException {
Boolean errorFound = new Boolean(true);
int totalFiles = 0;
PdfArray filesArray;
PdfDictionary root;
PdfDictionary names;
PdfDictionary embeddedFiles;
PdfReader reader = null;
String theResult = "unknown";
try {
if (!theBaseFile.toLowerCase().endsWith(".pdf"))
theResult = "file not PDF";
else {
reader = new PdfReader(theBaseFile);
root = reader.getCatalog();
names = root.getAsDict(PdfName.NAMES);
if (names == null){
theResult = "0";
errorFound = false;
}
else {
embeddedFiles = names.getAsDict(PdfName.EMBEDDEDFILES);
filesArray = embeddedFiles.getAsArray(PdfName.NAMES);
if (filesArray != null)
totalFiles = filesArray.size();
else {
filesArray = embeddedFiles.getAsArray(PdfName.KIDS);
if (filesArray != null){
for (int i = 0; i < filesArray.size(); i++)
totalFiles += filesArray.getAsDict(i).getAsArray(PdfName.NAMES).size();
}
}
theResult = String.format("%d", totalFiles / 2);
reader.close();
errorFound = false;
}
}
}
catch (Exception e) {
theResult = "unknown" + e.getMessage();
}
finally {
if (reader != null)
reader.close();
}
if (errorFound)
sendError(theResult);
return theResult;
}
I am migrating a webapp from Java 8 to 11 (and Tomcat 8 to 9) and i have a Client that downloads ZIP Archive Files from a Service using the following methods:
public HTTPResponse doGet(String aUrl, HashMap<String,String> aRequestParams, HashMap<String,String> aRequestProperties)
throws Exception
{
try
{
String lUrl = aUrl;
if (aRequestParams != null && aRequestParams.size() > 0)
{
StringBuffer lBodyStringBuffer = new StringBuffer();
for(String lParam : aRequestParams.keySet())
{
String lValue = aRequestParams.get(lParam);
if(lValue != null && !"".equals(lValue.trim()))
{
if(lBodyStringBuffer.length() > 0)
{
lBodyStringBuffer.append("&");
}
lBodyStringBuffer.append(URLEncoder.encode(lParam, sDEFAULTENCODING)).append("=").append(URLEncoder.encode(lValue, sDEFAULTENCODING));
}
}
String lParamString = lBodyStringBuffer.toString();
if (lParamString != null && lParamString.length() > 0)
{
if (!(lUrl.endsWith(sURLPARAMSLEADER) || aUrl.endsWith(sURLPARAMSSEPARATOR)))
{
if (lUrl.indexOf(sURLPARAMSLEADER) > -1)
{
lUrl = lUrl + sURLPARAMSSEPARATOR;
}
else
{
lUrl = lUrl + sURLPARAMSLEADER;
}
}
lUrl = lUrl + lParamString;
}
}
HttpURLConnection lConnection = createConnection(lUrl,sREQUESTETHOD_GET,null, aRequestProperties);
HTTPResponse lReturn = getResponseFromConnection(lConnection);
return lReturn;
}
catch(Exception lException)
{
throw new Exception("Fehler beim Durchführen der Anfrage: " + lException.getMessage(), lException);
}
}
private HTTPResponse getResponseFromConnection(HttpURLConnection aConnection)
throws Exception
{
InputStream lConnectionInputStream = null;
ByteArrayOutputStream lResponseByteArrayOutputStream = null;
try
{
aConnection.setRequestProperty("Accept", "application/zip");
int lStatusCode = aConnection.getResponseCode();
String lResponseCharset = getCharsetFromResponseContentType(aConnection.getContentType());
if (lResponseCharset == null)
{
if (lResponseCharset == null ||lResponseCharset.trim().length() == 0)
{
lResponseCharset = "UTF-8";
}
}
if (HttpURLConnection.HTTP_OK == lStatusCode)
{
lConnectionInputStream = aConnection.getInputStream();
}
else
{
lConnectionInputStream = aConnection.getErrorStream();
}
String lMessage = "";
if (lConnectionInputStream != null)
{
lResponseByteArrayOutputStream = new ByteArrayOutputStream();
int lBufferSize = 4096;
byte[] lBuffer = new byte[lBufferSize];
int lLength = 0;
while ((lLength = lConnectionInputStream.read(lBuffer, 0, lBufferSize)) != -1)
{
lResponseByteArrayOutputStream.write(lBuffer, 0, lLength);
}
byte[] lResponseByte = lResponseByteArrayOutputStream.toByteArray();
lMessage = new String (lResponseByte,lResponseCharset);
}
HTTPResponse lReturn = new HTTPResponse(lStatusCode, lMessage);
return lReturn;
}
catch(Exception lException)
{
throw lException;
}
finally
{
if (lResponseByteArrayOutputStream != null)
{
try{lResponseByteArrayOutputStream.close();}catch(Exception e){}
}
if (lConnectionInputStream != null)
{
try{lConnectionInputStream.close();}catch(Exception e){}
}
}
}
This is how i actually call the service via HTTP Get and save the data:
HTTPResponse lResponse = new HTTPRequest().doGet("http://localService.com/, null, null);
FileOutputStream lFileOutputStream = new FileOutputStream("exampleFile.zip", false);
lFileOutputStream.write(lResponse.getMessage().getBytes());
lFileOutputStream.close();
So this used to Work before and i am getting a headache about what might have changed. When i download the ZIP File with url in my Browser, everything seems fine, so the Service seems to work. But with my client the ZIP Files get corrupted and cannot be opened. The are not empty but they differ in size: surprisingly the corrupted files are about 50% larger than the ones downloaded via browser.
Does anyone know what the problem here is?
Ok,the problem was the return type String of the method getResponseFromConnection. I changed it and now write the file directly with the File.copy() method which VGR suggested.
This question already has answers here:
Find location of a removable SD card
(24 answers)
Closed 4 years ago.
I need SdCard path to save files in it. I have tried some codes but these code didn't work on some devices or Android versions. Now I need a code/path that get SdCard path for all device and all Android versions.
For getting sdcard path,try following code:
public static String getExternalSDCardRootDirectory() {
String cmdMOUNT = "cat /proc/mounts";
Runtime run = Runtime.getRuntime();
List<String> paths = new ArrayList<>();
try {
Process p = run.exec(cmdMOUNT);
BufferedInputStream in = new BufferedInputStream(p.getInputStream());
BufferedReader inBr = new BufferedReader(new InputStreamReader(in));
String lineStr;
while ((lineStr = inBr.readLine()) != null) {
Log.d(TAG, lineStr);
if (lineStr.toLowerCase().contains("sdcard") || lineStr.toLowerCase().contains("ext") ) {
String[] strArray = lineStr.split(" ");
if (strArray.length >= 3 &&
(!strArray[1].contains("/system") &&
!strArray[1].contains("/data") &&
!strArray[1].contains("/cache") &&
!strArray[1].contains("/persist")
)) {
String result = strArray[1].trim();
if((result.contains("ext") || result.contains("1")) && result.contains("storage")) {
paths.add(result);
}
//return result;
}
}
if (p.waitFor() != 0 && p.exitValue() == 1) {
Log.e(TAG, "check mount info failed");
return null;
}
}
inBr.close();
in.close();
} catch (Exception e) {
e.printStackTrace();
return null;
}
if (paths.size() > 0) {
return paths.get(0);
}
else {
return null;
}
}
For getting path you need to call Environment.getExternalStorageState()
I've found an existing post.
Simply change it to...
public static HashSet<String> getExternalMounts() {
final HashSet<String> out = new HashSet<String>();
String reg = "(?i).*vold.*(vfat|ntfs|exfat|fat32|ext3|ext4).*rw.*";
String s = "";
try {
final Process process = new ProcessBuilder().command("mount")
.redirectErrorStream(true).start();
process.waitFor();
final InputStream is = process.getInputStream();
final byte[] buffer = new byte[1024];
while (is.read(buffer) != -1) {
s = s + new String(buffer);
}
is.close();
} catch (final Exception e) {
e.printStackTrace();
}
// parse output
final String[] lines = s.split("\n");
for (String line : lines) {
if (!line.toLowerCase(Locale.US).contains("asec")) {
if (line.matches(reg)) {
String[] parts = line.split(" ");
for (String part : parts) {
if (part.startsWith("/"))
if (!part.toLowerCase(Locale.US).contains("vold"))
out.add(part);
}
}
}
}
return out;
}
The tested solution on different platforms can be found here.
I have a servlet which receives a huge string (apprx 301695 length) as a post parameter.
Every minute, a .net application sends such huge string to the servlet.
Initially I used to get the string as below:
Line 1: String str = request.getParameter("data");
But, after 3-4 hours. I get the following exception:
java.lang.OutOfMemoryError: Java heap space
Then I commented Line: 1. Even though, My servlet code does not receive the string, I get the same exception as mentioned above.
Please guide me. How should I deal with this issue? I have read many blogs and articles related to it, increased the heap size and other things. But, haven't found any solution.
Original code was like below:
private String scanType = "";
private static final String path = "D:\\Mobile_scan_alerts";
private static final String stockFileName = "stock.txt";
private static final String foFileName = "fo.txt";
private static Logger logger = null;
private String currDate = "";
private DateFormat dateFormat;
private StringBuffer stockData;
private StringBuffer foData;
StringBuffer data = new StringBuffer("");
// For average time of received data
private static float sum = 0;
private static float count = 0;
private static float s_sum = 0;
private static float s_count = 0;
private static float fo_sum = 0;
private static float fo_count = 0;
private static final File dir = new File(path);
private static final File stockFile = new File(path + "\\" + stockFileName);
private static final File foFile = new File(path + "\\" + foFileName);
public void init() {
logger = MyLogger.getScanAlertLogger();
if(logger == null) {
MyLogger.createLog();
logger = MyLogger.getScanAlertLogger();
}
}
/**
* Processes requests for both HTTP <code>GET</code> and <code>POST</code>
* methods.
*
* #param request servlet request
* #param response servlet response
* #throws ServletException if a servlet-specific error occurs
* #throws IOException if an I/O error occurs
*/
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
PrintWriter out = response.getWriter();
response.setContentType("text/plain");
String strScan = "";
try {
String asof = null;
scanType = request.getParameter("type");
scanType = scanType == null ? "" : scanType;
if(scanType.length() > 0){
if(scanType.equalsIgnoreCase("s")) {
stockData = null;
stockData = new StringBuffer(request.getParameter("scanData"));
stockData = stockData == null ? new StringBuffer("") : stockData;
} else {
foData = null;
foData = new StringBuffer(request.getParameter("scanData"));
foData = foData == null ? new StringBuffer("") : foData;
}
}
asof = request.getParameter("asof");
asof = asof == null ? "" : asof.trim();
// Date format without seconds
DateFormat formatWithoutSec = new SimpleDateFormat("yyyy/MM/dd HH:mm");
dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date tmp = new Date();
// format: yyyy/MM/dd HH:mm:ss
currDate = dateFormat.format(tmp);
//format: yyyy/MM/dd HH:mm
Date asofDate = formatWithoutSec.parse(asof);
Date cDate = formatWithoutSec.parse(currDate);
cDate.setSeconds(0);
System.out.println(asofDate.toString()+" || "+cDate.toString());
int isDataExpired = asofDate.toString().compareTo(cDate.toString());
if(isDataExpired > 0 || isDataExpired == 0) {
if(scanType != null && scanType.length() > 0) {
checkAndCreateDir();
strScan = scanType.equalsIgnoreCase("s") ? "Stock Data Recieved at "+currDate
: "FO Data Recieved at "+currDate;
//System.out.println(strScan);
} else {
strScan = "JSON of scan data not received properly at "+currDate;
//System.out.println("GSAS: received null or empty");
}
} else {
strScan = "GSAS: " + scanType + ": Received Expired Data of "+asofDate.toString()+" at "+cDate.toString();
System.out.println(strScan);
}
scanType = null;
} catch (Exception ex) {
strScan = "Mobile server issue for receiving scan data";
System.out.println("GSAS: Exception-1: "+ex);
logger.error("GetScanAlertServlet: processRequest(): Exception: "+ex.toString());
} finally {
logger.info("GetScanAlertServlet: "+strScan);
out.println(strScan);
}
}
private void checkAndCreateDir() {
try {
boolean isStock = false;
Date ddate = new Date();
currDate = dateFormat.format(ddate);
sum += ddate.getSeconds();
count++;
logger.info("Total Average Time: "+(sum/count));
if(scanType.equalsIgnoreCase("s")){ //For Stock
setStockData(stockData);
Date date1 = new Date();
currDate = dateFormat.format(date1);
s_sum += date1.getSeconds();
s_count++;
logger.info("Stock Average Time: "+(s_sum/s_count));
//file = new File(path + "\\" + stockFileName);
isStock = true;
} else if (scanType.equalsIgnoreCase("fo")) { //For FO
setFOData(foData);
Date date2 = new Date();
currDate = dateFormat.format(date2);
fo_sum += date2.getSeconds();
fo_count++;
logger.info("FO Average Time: "+(fo_sum/fo_count));
//file = new File(path + "\\" +foFileName);
isStock = false;
}
if(!dir.exists()) { // Directory not exists
if(dir.mkdir()) {
if(isStock)
checkAndCreateFile(stockFile);
else
checkAndCreateFile(foFile);
}
} else { // Directory already exists
if(isStock)
checkAndCreateFile(stockFile);
else
checkAndCreateFile(foFile);
}
} catch (Exception e) {
System.out.println("GSAS: Exception-2: "+e);
logger.error("GetScanAlertServlet: checkAndCreateDir(): Exception: "+e);
}
}
private void checkAndCreateFile(File file) {
try{
if(!file.exists()){ // File not exists
if(file.createNewFile()){
writeToFile(file);
}
} else { // File already exists
writeToFile(file);
}
} catch (Exception e) {
System.out.println("GSAS: Exception-3: "+e);
logger.error("GetScanAlertServlet: checkAndCreateFile(): Exception: "+e.toString());
}
}
private void writeToFile(File file) {
FileOutputStream fop = null;
try{
if(scanType.equalsIgnoreCase("s")){ //For Stock
data = getStockData();
} else if (scanType.equalsIgnoreCase("fo")) { //For FO
data = getFOData();
}
if(data != null && data.length() > 0 && file != null){
fop = new FileOutputStream(file);
byte[] contentBytes = data.toString().getBytes();
for(byte b : contentBytes){
fop.write(b);
}
//fop.write(contentBytes);
fop.flush();
} else {
System.out.println("GSAS: Data is null/empty string");
logger.info("GSAS: Data is null or empty string");
}
data = null;
} catch (Exception e) {
System.out.println("GSAS: Exception-4: "+e);
logger.info("GetScanAlertServlet: writeToFile(): Exception: "+e.toString());
} finally {
try {
if(fop != null)
fop.close();
} catch (IOException ex) {
java.util.logging.Logger.getLogger(GetScanAlertServlet.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
private String readFromFile(String fileName){
String fileContent = "";
try{
String temp = "";
File file = new File(fileName);
if(file.exists()){
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
while((temp = br.readLine()) != null)
{
fileContent += temp;
}
br.close();
} else {
System.out.println("GSAS: File not exists to read");
logger.info("GetScanAlertServlet: File not exists to read");
}
temp = null;
file = null;
} catch (Exception e) {
System.out.println("GSAS: Exception-5: "+e);
logger.error("GetScanAlertServlet: readFromFile(): Exception: "+e.toString());
}
return fileContent;
}
public StringBuffer getStockData() {
//String temp="";
//StringBuffer temp = (StringBuffer)scanDataSession.getAttribute("stock");
//if(temp != null && temp.length() > 0) {
// return temp;
//}
if(stockData != null && stockData.length() > 0){
return stockData;
} else {
stockData = null;
stockData = new StringBuffer(readFromFile(path + "\\"+ stockFileName));
return stockData;
}
}
public StringBuffer getFOData(){
//String temp="";
//StringBuffer temp = (StringBuffer)scanDataSession.getAttribute("fo");
//if(temp != null && temp.length() > 0) {
// return temp;
//}
if(foData != null && foData.length() > 0) {
return foData;
} else {
foData = null;
foData = new StringBuffer(readFromFile(path + "\\" + foFileName));
return foData;
}
}
}
Increasing heap size is not a good solution for this problem. Your upstream application should stop sending huge strings to your Servlet.
Your upstream(.net) application should consider writing all the data to a file, just need to send the location of the file as a parameter to your Servlet. Once your servlet receives notification from the upstream, you consider downloading/reading file from the location.
Then I commented Line: 1. Even though, My servlet code does not
receive the string (as commented), I get the same exception as
mentioned above.
The Line: 1 is to read data. If you comment it, you wont receive the String.
You can use apache commons-fileupload library Streaming API, this way, you get your uploaded file as a stream and write it to the file :
ServletFileUpload upload = new ServletFileUpload();
// Parse the request
FileItemIterator iter = upload.getItemIterator(request);
while (iter.hasNext()) {
FileItemStream item = iter.next();
String name = item.getFieldName();
InputStream stream = item.openStream();
if (item.isFormField()) {
System.out.println("Form field " + name + " with value "
+ Streams.asString(stream) + " detected.");
} else {
System.out.println("File field " + name + " with file name "
+ item.getName() + " detected.");
// Process the input stream
...
}
}
Now You have InputStream, so you can write it in the output stream.
But to use this you need your .NET application to upload the bytes to the server instead of sending entire String as request param.
http://commons.apache.org/proper/commons-fileupload/streaming.html
Please check your VM Arguments and modify them approriately if you have no control of the String being passed to the servlet. For examples:
set JAVA_OPTS=-Dfile.encoding=UTF-8 -Xms128m -Xmx1024m -XX:PermSize=64m -XX:MaxPermSize=256m
Check for a complete explanation here.
We used GZip compression/decompression to lower the size of the string. And it worked effectively.
So, the .net service compressed the huge string, sent it to our Servlet. We then decompress it at our server.
Currently my code accesses my Gmail inbox with IMAP (imaps) and JavaMail, for the purpose of reading emails sent to myself from newest to oldest, identifying which ones have attachments in the .zip or .xap format. If found, the email's subject is displayed and asks if I want to download the attachment.
If I click no, it continues searching. If I click yes, it calls the createFolder method to create a directory, saves the attachment there, and then extracts it.
Problem: The most recent email in my inbox has a .zip file so it is quickly found, but if I click "No" it takes upwards of 20 seconds to find the next email containing a zip/xap for 2 reasons: (1) There are 20+ emails more recent (2) There are 2 emails more recent containing attachments BUT NOT zip/xap.
I'm guessing this is due to the recursion that's occuring to isolate attachments before identifying their format, or some other redundant code/method? I've read here and here that a Fetch Profile can help, instead of contacting the server unnecessarily.
I'm hoping to decrease the delay substantially. Is Fetch/Envelope the way to go? Is my code a tangled mess, or can you share a sample solution? Thank you!
Full Code:
public class ReceiveMailImap {
public ReceiveMailImap() {}
public static void doit() throws MessagingException, IOException {
Folder inbox = null;
Store store = null;
try {
Properties props = System.getProperties();
Session session = Session.getDefaultInstance(props, null);
//session.setDebug(true);
store = session.getStore("imaps");
store.connect("imap.gmail.com", "myAccount#gmail.com", "myPassword");
inbox = store.getFolder("Inbox");
inbox.open(Folder.READ_WRITE);
Message messages[] = inbox.getMessages();
// Loop newest to oldest
for (int i = messages.length - 1; i >= 0; i--) {
Message msg = messages[i];
//If current msg has no attachment, skip.
if (!hasAttachments(msg)) {
continue;
}
String from = "Sender Unknown";
if (msg.getReplyTo().length >= 1) {
from = msg.getReplyTo()[0].toString();
} else if (msg.getFrom().length >= 1) {
from = msg.getFrom()[0].toString();
}
subject = msg.getSubject();
if (from.contains("myAccount#gmail.com")) {
//Get My Documents
subject = subject.replaceAll("[^a-zA-Z0-9.-]", "_");
//Call Save Attachment -->>
saveAttachment(msg.getContent());
msg.setFlag(Flags.Flag.SEEN, true);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (inbox != null) {
inbox.close(true);
}
if (store != null) {
store.close();
}
}
}
public static boolean hasAttachments(Message msg) throws MessagingException, IOException {
if (msg.isMimeType("multipart/mixed")) {
Multipart mp = (Multipart) msg.getContent();
if (mp.getCount() > 1) return true;
}
return false;
}
public static void saveAttachment(Object content)
throws IOException, MessagingException {
OutputStream out = null;
InputStream in = null;
try {
if (content instanceof Multipart) {
Multipart multi = ((Multipart) content);
int parts = multi.getCount();
for (int j = 0; j < parts; ++j) {
MimeBodyPart part = (MimeBodyPart) multi.getBodyPart(j);
if (part.getContent() instanceof Multipart) {
// part-within-a-part, do some recursion...
saveAttachment(part.getContent());
} else {
int allow = 0;
if (part.isMimeType("application/x-silverlight-app")) {
extension = "xap";
allow = 1;
} else {
if (part.isMimeType("application/zip")) {
extension = "zip";
allow = 1;
}
}
if (allow == 1) {
int dialogResult = JOptionPane.showConfirmDialog(null, "The most recent file is: " + subject + " Would you like to download this file?", "Question", 0);
if (dialogResult == JOptionPane.YES_OPTION) {
savePath = createFolder(subject) + "\\" + subject + "." + extension;
} else {
continue;
}
out = new FileOutputStream(new File(savePath)); in = part.getInputStream();
int k;
while ((k = in .read()) != -1) {
out.write(k);
}
//Unzip
savePath = savePath.toString();
Unzip unzipFile = new Unzip();
unzipFile.UnZipper(dir, savePath);
} else {
continue;
}
}
}
}
} finally {
if ( in != null) { in .close();
}
if (out != null) {
out.flush();
out.close();
}
}
}
public static File createFolder(String subject) {
JFileChooser fr = new JFileChooser();
FileSystemView myDocs = fr.getFileSystemView();
String myDocuments = myDocs.getDefaultDirectory().toString();
dir = new File(myDocuments + "\\" + subject);
savePathNoExtension = dir.toString();
dir.mkdir();
return dir;
}
public static void main(String args[]) throws Exception {
ReceiveMailImap.doit();
}
}
A FetchProfile allows you to prefetch some of the message information "in bulk". This prefetched information is then used later when you access the corresponding fields of the Message objects. You probably want to use FetchProfile.Item.CONTENT_INFO and FetchProfile.Item.ENVELOPE. Other than that, your code looks fine.