PDFBox: Disable Font Cache or change its location - java

When I call PDField.setValue to set the value for a form field, I get the following stacktrace:
FileSystemFontProvider.saveDiskCache(349) | Could not write to font cache
java.io.FileNotFoundException: /.pdfbox.cache (Permission denied)
at java.io.FileOutputStream.open(Native Method)
at java.io.FileOutputStream.<init>(FileOutputStream.java:194)
at java.io.FileOutputStream.<init>(FileOutputStream.java:145)
at java.io.FileWriter.<init>(FileWriter.java:73)
at org.apache.pdfbox.pdmodel.font.FileSystemFontProvider.saveDiskCache(FileSystemFontProvider.java:290)
at org.apache.pdfbox.pdmodel.font.FileSystemFontProvider.<init>(FileSystemFontProvider.java:226)
at org.apache.pdfbox.pdmodel.font.FontMapperImpl$DefaultFontProvider.<clinit>(FontMapperImpl.java:130)
at org.apache.pdfbox.pdmodel.font.FontMapperImpl.getProvider(FontMapperImpl.java:149)
at org.apache.pdfbox.pdmodel.font.FontMapperImpl.findFont(FontMapperImpl.java:413)
at org.apache.pdfbox.pdmodel.font.FontMapperImpl.findFontBoxFont(FontMapperImpl.java:376)
at org.apache.pdfbox.pdmodel.font.FontMapperImpl.getFontBoxFont(FontMapperImpl.java:350)
at org.apache.pdfbox.pdmodel.font.PDType1Font.<init>(PDType1Font.java:145)
at org.apache.pdfbox.pdmodel.font.PDType1Font.<clinit>(PDType1Font.java:79)
at org.apache.pdfbox.pdmodel.font.PDFontFactory.createFont(PDFontFactory.java:62)
at org.apache.pdfbox.pdmodel.PDResources.getFont(PDResources.java:143)
at org.apache.pdfbox.pdmodel.interactive.form.PDDefaultAppearanceString.processSetFont(PDDefaultAppearanceString.java:164)
at org.apache.pdfbox.pdmodel.interactive.form.PDDefaultAppearanceString.processOperator(PDDefaultAppearanceString.java:131)
at org.apache.pdfbox.pdmodel.interactive.form.PDDefaultAppearanceString.processAppearanceStringOperators(PDDefaultAppearanceString.java:107)
at org.apache.pdfbox.pdmodel.interactive.form.PDDefaultAppearanceString.<init>(PDDefaultAppearanceString.java:85)
at org.apache.pdfbox.pdmodel.interactive.form.PDVariableText.getDefaultAppearanceString(PDVariableText.java:93)
at org.apache.pdfbox.pdmodel.interactive.form.AppearanceGeneratorHelper.<init>(AppearanceGeneratorHelper.java:94)
at org.apache.pdfbox.pdmodel.interactive.form.PDTextField.constructAppearances(PDTextField.java:262)
at org.apache.pdfbox.pdmodel.interactive.form.PDTerminalField.applyChange(PDTerminalField.java:228)
at org.apache.pdfbox.pdmodel.interactive.form.PDTextField.setValue(PDTextField.java:218)
I am running PDFBox 2.0.4 which is the newest version. My webserver most likely does not have access to write to .pdfbox.cache in the default location (which seems to be the JVM property user.home). Is there any way to disable the disk caching or change the location of the cache file?
I did notice that I can set a JVM wide system property called pdfbox.fontcache, but my webapp shares a jvm with other applications so this isn't an optimal solution. I also tried using that solution and setting the pdfbox.fontcache to /tmp, but it didn't actually create a file (although it now only throws the stacktrace once per boot).
I looked into the code in the FileSystemFontProvider and the problematic code seems to be in the saveDiskCache method. In that method, it first tries to write the file, but a FileNotFoundException is thrown instead of a SecurityException. FileNotFoundException inherits from IOException.
File file = getDiskCacheFile();
try
{
writer = new BufferedWriter(new FileWriter(file));
}
catch (SecurityException e)
{
return;
}

When you set pdfbox.fontcache with a temporary folder like /tmp where your JVM can write new file inside then a cache file called .pdfbox.cache can be created when you generate PDF with PDFBox (I also use PDFBox 2.0.4).
Maybe your JVM cannot create a new file inside your /tmp directory? To check this try to create a new file with the user running your JVM with an interactive command prompt (shell).
With the command ls -lA /tmp you should see a .pdfbox.cache file in the temporary folder that you configure (example with a tomcat JVM and user):
-rw-r--r-- 1 tomcat tomcat 2050 Dec 29 16:13 .pdfbox.cache
It's not an optimal solution because you can't set multiple pdfbox.fontcache system property on a single JVM.

Related

OpenWhisk action opening file gets file not found exception, but file exists

Testing my action via wsk command when in the vagrant VM it gets the parameters successfully but when attempting to open a file it throws:
FileNotFoundException: /ild/data/workspaceArtifacts/workspaceArtifacts_bc3d43ab-1529-41c8-8571-b7155e53e3ff.json
However, when I list the file it is there:
ls -l /ild/data/workspaceArtifacts/workspaceArtifacts_bc3d43ab-1529-41c8-8571-b7155e53e3ff.json
-rw-r--r-- 1 vagrant vagrant 37457375 Jul 6 21:57 /ild/data/workspaceArtifacts/workspaceArtifacts_bc3d43ab-1529-41c8-8571-b7155e53e3ff.json
Does OpenWhisk (running locally) have sandbox limitations for where it is allowed to open files? My action is a Java action and I'm attempting to open a FileReader.
All directories referenced are owned by vagrant:vagrant and have read permissions for all.
Openwhisk runs actions inside a docker container and the files outside the container won't be visible to the action. You can zip the files along with the code and create the action. You can look at this for reference.
https://www.raymondcamden.com/2017/01/10/creating-packaged-actions-in-openwhisk
https://console.bluemix.net/docs/openwhisk/openwhisk_actions.html#openwhisk_actions

Failed to delete a file in Windows using Java

I have been trying to delete a file in windows operating system using the Java IO file.delete() API. However it fails and returns false. The same code works like a charm in Ubuntu.
I have verified that the permissions of the file allows the program to delete it. Also all the input and output stream for the file has been opened as try with resources.
try (InputStream in = new FileInputStream(localFile); OutputStream out = new FileOutputStream(destinationFileName))
Using a debugger I have tested and found out that at the code line that I delete the file it returns true for following API calls.
file.exists()
file.canRead();
file.canWrite();
file.canExecute();
I have even tried adding System.gc() right before calling delete to make sure all the streams are closed.
Not sure whether this is helpful information but I have even tried using the Apache commons FileUtils.forceDelete(file) method and it has also been failed.
So what am I missing here?
Update:
By using Files.delete(Paths.get(file.getAbsolutePath())) I got the following error.
java.nio.file.FileSystemException: C:\Users\thuvvareka\Desktop\temp\in\sd.xml: The process cannot access the file because it is being used by another process.
at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:86)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102)
at sun.nio.fs.WindowsFileSystemProvider.implDelete(WindowsFileSystemProvider.java:269)
at sun.nio.fs.AbstractFileSystemProvider.delete(AbstractFileSystemProvider.java:103)
at java.nio.file.Files.delete(Files.java:1126)
at org.adroitlogic.x.transport.file.FileMessageInjector.finalizeProcessing(FileMessageInjector.java:161)
at org.adroitlogic.x.transport.file.FileMessageInjector.afterProcess(FileMessageInjector.java:123)
at org.adroitlogic.x.transport.file.FileMessageInjector.afterProcess(FileMessageInjector.java:37)
at org.adroitlogic.x.base.trp.ScheduledMessageInjector.lambda$2(ScheduledMessageInjector.java:72)
at org.adroitlogic.x.api.trp.MessageReceiver.lambda$receive$3(MessageReceiver.java:100)
at java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:760)
at java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:736)
at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:474)
at java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:1962)
at org.adroitlogic.x.core.MessageContext.lambda$createNewResponseFuture$2(MessageContext.java:459)
at java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:760)
at java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:736)
at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:474)
at java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:1962)
at org.adroitlogic.x.core.MessageContext.completeMessageFlowSuccessfully(MessageContext.java:332)
at org.adroitlogic.x.base.connector.EgressConnectorElement.sendMessage(EgressConnectorElement.java:185)
at org.adroitlogic.x.base.connector.EgressConnectorElement.process(EgressConnectorElement.java:146)
at org.adroitlogic.x.base.processor.AbstractProcessingElement.processMessage(AbstractProcessingElement.java:103)
at org.adroitlogic.x.base.processor.TraceableProcessingElement.processMessage(TraceableProcessingElement.java:53)
at org.adroitlogic.x.base.connector.IngressConnectorElement.receiveMessage(IngressConnectorElement.java:119)
at org.adroitlogic.x.core.IntegrationPlatform.lambda$receive$0(IntegrationPlatform.java:81)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Welcome to Windows.
java.nio.file.FileSystemException: C:\Users\thuvvareka\Desktop\temp\in\sd.xml:
The process cannot access the file because it is being used by another process.
Typically, when a process has a file open in Windows, the operating system locks the file in a way that the file cannot be deleted. If it's your program that has the file open while you are trying to delete it, then close the file first and then delete it. If it's another program that has the file open, then you'll need to figure out who has it open and go from there.
When a process has a file open in Linux, there is typically nothing preventing you from deleting it, which is why you see different behavior.
I ran into this recently. I created a workaround where if file.delete() returns false I check if file.exists() returns true and if so, I wait a bit then try again and give up after some number of tries.
My unproven suspicion is that virus checkers on Windows lock the file to examine the file and waiting allows the virus checker to finish.
// Remove the original file.
if(!file.delete()) {
// wait a bit then retry on Windows
if (file.exists())
{
for (int i = 0; i < 6; i++)
{
Thread.sleep(500);
System.gc();
if (file.delete())
break;
}
Use Files.delete(filePath) instead of file.delete() as file.delete() has some issue regarding permission on windows.
I had the same issue.
Do out.close(); solve it.
System.gc() will not remove link to the OutputStream as long as you don't have close it.
Maybe you can use System.Runtime.exec() to run a terminal / command line command to delete a specific file. This may be somehow platform dependent, but the command to be entered to the exec() function may differ among os properties.
You can check this thread to determine the current os of the java program running.
How do I programmatically determine operating system in Java?
In linux, your line would be as follows:
System.Runtime.exec("rm <path to file>");

IOException when creating a temporary file?

I'm creating a task plugin for Atlassian Bamboo. At some moment of task executing, I would like to create a temporary file:
File temp = File.createTempFile(fileName.toString(), null, dir);
temp.deleteOnExit();
, where:
fileName.toString() = e.g. "C:\Atlassian\bamboo-home\xml-data\build-dir\CMPT-CMPTP-JOB1\test.java"
dir = new File("temp");
When testing this locally, everything works fine - the file is created properly. However, after I deploy plugin on server and try to execute above code, I've got an IOException:
java.io.IOException: The filename, directory name, or volume label syntax is incorrect
at java.io.WinNTFileSystem.createFileExclusively(Native Method)
at java.io.File.createTempFile(File.java:1879)
What could be the reason?
Additional info: I'm pretty sure that dir.exists() .
A file name of
"C:\Atlassian\bamboo-home\xml-data\build-dir\CMPT-CMPTP-JOB1\test.java"
is valid on Windows but is invalid on Unix operating systems. You won't be able to create a (temp) file like that, either as specified as the absolute name/path or the file nor just relative to another folder.
If your OS is Windows, you still can't use a full path (starting with drive specification like "C:") to be created as a child of another folder.
You could have spaces in the beginning or the ending of your path, print your file.getAbsolutePath() in order to see the current path where java is reading.
The dir variable must be set with the full (or relative) path to the directory temp. The first arg of File.createTempFile should be the prefix of the temp file (at least three letter long. for exeample "test"). This will create a "test.tmp" in the given directory (specified by the variable dir).
Check the javadoc
You can check existence of the directory dir with dir.exists()

Servlet - Addressing properties files

I have a simple Servlet that needs to pass some properties files to another class.
Properties prop = new Properties();
prop.load(new FileInputStream("/home/user/config.properties"));
Above works fine.
But I can't address the right absolute path in below:
String protocol = prop.getProperty("protocol", "/home/user/protocol.properties");
String routes = prop.getProperty("routes", "/home/user/routes.properties");
MyClass message = new MyClass(protocol, routes, 0);
At the end I receive below from tomcat log:
INFO: Server startup in 3656 ms
java.io.FileNotFoundException: routes.properties (No such file or directory)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at java.io.FileInputStream.<init>(FileInputStream.java:97)
at com.cc.verticals.Messenger.<init>(Messenger.java:134)
at com.foo.MyClass.<init>(MyClass.java:42)
at com.verticals.cc.util.VerticalUtil.setup(VerticalUtil.java:59)
at com.verticals.cc.util.VerticalUtil.main(VerticalUtil.java:259)
at com.verticals.cc.dao.VerticalDao.<init>(VerticalDao.java:24)
at com.verticals.cc.controller.VerticalController.<init>(VerticalController.java:33)
Line 42 is pointing to the constructor where routes.properties file goes in.
Messenger line 134 points to:
prop.load(new FileInputStream(routesFilename));
Any Idea how to address the properties files and send them as a String parameter? Thanks.
By the looks of it (I prefer if you post the content's of the properties files), there is a property within config.properties such that routes = routes.properties. When you call new file(routes); you get the FileNotFoundException because you are trying to open routes.properties in the current working directory where java was launched (which doesn't exist)
As a side note, you using one property file to reference another property, which is fine but a bit odd or unconventional. Further, you should stick these files in a 'resource' folder to remove absolute paths and gain portability.
Notice that prop.getProperty method cannot throw FileNotFoundException. So that exception must have been thrown earlier on prop.load();
Please make sure that you have opened the permissions on the file. Open a terminal and issue following command:
$ chmod 777 /home/user/routes.properties
$ chmod 777 /home/user/protocol.properties

Deployment in tomcat

i am getting a problem
i have deployed a war file, when i run localy through tomcat it works fine but when i run on another system by giveing my system ip and then project folder e.g
http:\192.168.0.145\DllTest it loads the applet but when i click on a button to load the functionality it is throwing an exception
Exception in thread "AWT-EventQueue-3" java.lang.UnsatisfiedLinkError: Expecting an absolute path of the library: http:\192.168.0.145:8080\DllTest\lib\jinvoke.dll
while it is working fine localy but not in another system. Please tell me what is the problem.
Is it a rights issue or something else.
You cannot load a DLL on an external host. It has to be an absolute disk file system -as the exception message already hints. Your best bet is to download it manually, create a temp file and load it instead.
File dllFile = File.createTempFile("jinvoke", ".dll");
InputStream input = new URL(getCodeBase(), "lib/jinvoke.dll").openStream();
OuptutStream output = new FileOutputStream(dllFile);
// Write input to output and close streams the usual Java IO way.
// Then load it using absolute disk file system path.
System.loadLibrary(dllFile.getAbsolutePath());
dllFile.deleteOnExit();

Categories