Java getResourceAsStream cannot load resource - resources

I am trying to load a class whose name is specified in a properties file. Here is the code for the same.
try {
Properties properties = new Properties();
InputStream in = MyAbstractFactory.class.getResourceAsStream("/some.properties");
properties.load(in);
String impl = properties.getProperty("key");
MyAbstractFactory factories = (MyAbstractFactory) Class.forName( impl ).newInstance();
return factories;
} catch (Exception e) {
return new DefaultFactoriesImpl();
}
This code is part of a jar file. the properties file is just outside the jar. Its unable to load the properties file and is loading DefaultFactoriesImpl instead. I know this happens when MyAbstractFactory.class.getResourceAsStream cant find the resource in the class path but that doesn't seem to be the case here.
Dir Structure:-
com
myjar.jar
some.properties
Command i am executing is "java -jar myjar.jar"
Any feedback on why this might be happening. Could this have something to do with Clasloaders? I'd like to add that when i run this code from within eclipse it seems pick up some.properties just fine.

Remove the leading slash from the argument you pass to getResourceAsStream().
Put the folder outside the JAR into the CLASSPATH when you execute the JAR. I don't know if the manifest CLASSPATH overrides the one you might pass using -cp. Play with it; one of them will work.
It's not finding your .properties file because it's not in the JVM CLASSPATH. When you do it properly, the JVM will find it.

Related

kofax export script project setup

For my first export script I took the KCEC example and the APIRefExport.chm documentation to create my project by replacing the example code with my own.
I would like to create a clean export script from scratch.
I created a new class library project and called it EmptyExportScript (placeholder). The target framework is .Net 4. The platform target is x86 and the output path is .....\Program Files (x86)\Kofax\CaptureSS\ServLib\Bin\. When debugging I would like to start the administration module so I set this path .......\Program Files (x86)\Kofax\CaptureSS\ServLib\Bin\.
The option "Make assembly COM-Visible" is checked and I added the Kofax.ReleaseLib.Interop.dll to the references.
For the KfxReleaseScript.cs I added this code
[ClassInterface(ClassInterfaceType.None)]
[ProgId("KFXTS.EmptyExportScript.KfxReleaseScript")]
public class KfxReleaseScript
{
public ReleaseData documentData;
// public KfxReturnValue OpenScript()
// public KfxReturnValue ReleaseDoc()
// public KfxReturnValue CloseScript()
}
For the KfxReleaseScriptSetup.cs I added this code
[ClassInterface(ClassInterfaceType.None)]
[ProgId("KFXTS.EmptyExportScript.KfxReleaseScriptSetup")]
public class KfxReleaseScriptSetup
{
public ReleaseSetupData setupData;
// public KfxReturnValue OpenScript()
// public KfxReturnValue CloseScript()
// public KfxReturnValue RunUI()
// public KfxReturnValue ActionEvent(KfxActionValue actionID, string data1, string data2)
}
Lastly I added a Form to the project when running the UI.
For registration I added a EmptyExportScript.inf with this content
[Scripts]
Empty Export
[Empty Export]
SetupModule=EmptyExportScript.dll
SetupProgID=KFXTS.EmptyExportScript.KfxReleaseScriptSetup
SetupVersion=10.2
ReleaseModule=EmptyExportScript.dll
ReleaseProgID=KFXTS.EmptyExportScript.KfxReleaseScript
ReleaseVersion=10.2
SupportsNonImageFiles=True
SupportsKofaxPDF=True
RemainLoaded=True
SupportsOriginalFileName=False
When building the project .dll and .inf file get placed into the kofax bin directory.
I recognized that other scripts have a .pdb and .dll.config file in there too.
How do I get them?
When trying to install the custom script, I can add it to the script installation manager but I can't install it. There is nothing to install so I think I'm missing the .pdb and .dll.config file.
Is anything else missing?
Thanks for help :)
Kofax does not need a pdb file, but they are handy if you want to debug your connector and attach it to the release.exe process (learn more about them here).
I would not recommend changing the output path itself to Capture\Bin, but rather create a post-build event:
For example, the following line copies all required files to a separate folder under the CaptureSS\Bin folder:
xcopy "$(TargetDir)*" "C:\Program Files (x86)\Kofax\CaptureSS\ServLib\Bin\SmartCAP\kec\SmartCAP.KEC.Template\" /Y /S
Having a dll.config file is possible, but rare. I would rather recommend storing process-specific data in a custom storage string object of the respective batch class definition (which has the added benefit that you can just import/export the definition along with the batch class, and that you can display and have it changed it in setup form). Having said all that, back to your initial issue - the connector can't be installed.
COM visibility
The assembly needs to be COM-visible, but you mentioned that it was. For the sake of completeness, here's what you will need to do. Note that the GUID must be unique (only relevant if you copied an existing solution):
If you're installing the connector on a different machine, you will need to register it first using regasm.exe - here's an example:
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe" SampleExport.dll /codebase /tlb:SampleExport.tlb
ProgIds
Then, your .inf file needs to contain the precise ProgIDs:
[Scripts]
SampleExport
[SampleExport]
SetupModule=SampleExport.dll
SetupProgID=SampleExport.Setup
SetupVersion=11.0
ReleaseModule=SampleExport.dll
ReleaseProgID=SampleExport
ReleaseVersion=11.0
SupportsNonImageFiles=True
SupportsKofaxPDF=True
Both your ReleaseScript.cs and ReleaseSetupScript.cs files need the correct attribute, for example:
[ProgId("SampleExport")]
public class ReleaseScript
If that all still does not work, please provide us with the detailed error message (to be found at CaptureSV\Logs).
I had to change the file format from UTF-8 to UTF-8 without BOM.
This worked for me.

karate: Picking up feature files from absolute class path

I am following the DemoTestSelected.java sample to run the feature file in my Karate Framework. It's working fine when i run them in intellij. But when i convert it into jar and then run from it, it is throwing the below error.
java.lang.RuntimeException: java.io.FileNotFoundException: file:\C:\Src_path\target\app-jar-with-dependencies.jar!\features\app\app_1.0.4_a.feature (The filename, directory name, or volume label syntax is incorrect)
I explored the Karate Core code and found the below class which might be problem.
public static URL toFileUrl(String path) {
path = StringUtils.trimToEmpty(path);
File file = new File(path);
try {
return file.getAbsoluteFile().toURI().toURL();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
I am stuck here, any help would be appreciated.
First - no one has ever reported this problem and teams normally don't need to bundle tests into a JAR.
Second - if you use the classpath: prefix, you should be able to load feature files from within even JAR files. So please use it and it is documented here: https://github.com/intuit/karate#reading-files
* def result = call read('classpath:some-reusable-steps.feature')
If this does not solve the problem, please follow the instructions here and submit an issue: https://github.com/intuit/karate/wiki/How-to-Submit-an-Issue - please explain what you are trying to do differently also.

How can ConfigSlurper's groovy file can call methods defined in build.gradle?

I am working on project whose build logic is defined in gradle and has a build.gradle file for it. Now, we would like to manage property of the project using groovy's config Sluper. And, I have placed config.groovy file in folder that contains all the Helper class for the project. The content of the conf.groovy file is below:
categories {
includeCategories = defaultIncludeCategories()
excludeCategories = defaultExcludeCategories()
}
String defaultIncludeCategories() {
def include = 'default'
if( isAbcJob() ) {
include = 'tier0'
}
logger.info "defaultIncludeCategories: $include"
include
}
Now, as you can see there is a method name isAbcJob() that I need to use in the configuration file but this method is present in build.gradle, which is the file that call conf.groovy file for property management.
Bottom line is how would conf.groovy script would know where isAbcJob() method is?
Please advice.
I found the following question that has been asked on Gradle forums very helpful. And, it looks like that accessing other gradle script's methods is not possible unless you access them through tasks:
https://discuss.gradle.org/t/multiple-apply-froms-dont-seem-to-import-all-methods/2274/6

Will InputStreamReader getResourceAsStream work in Linux?

I have this code in a Java EE Application for reading the Properties file.
Even though the Myservice.properties is placed under WEB-INF/classes folder, the properties aren't being read in Linux environment, but it is working fine in Windows environment.
InputStreamReader fMainProp = new InputStreamReader(this.getClass().getResourceAsStream("/Myservice.properties"));
Will the above will only work in windows?
MyWeb() {
prop = new Properties();
try {
InputStreamReader fMainProp = new InputStreamReader(this.getClass().getResourceAsStream("/Myservice.properties"));
prop.load(fMainProp);
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
Whether that code works depends on if the classloader which loaded the calling class as represented by getClass() in your code has access to the /WEB-INF/classes. Apparently the class in question is by itself not inside the /WEB-INF/classes or has a copy which is placed elsewhere in the classpath and server make/version used in the Linux environment uses a somewhat different classloader hierarchy than the server make/version used in the Windows environment.
Fact is, if you can't guarantee that the properties file is to be loaded by the same classloader as the calling class, then you should not try to get it by the classloader of the calling class, but by the context class loader of the current thread. It has access to everything.
prop.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("Myservice.properties"));
Please note that with this class loader, the path cannot be relative. So don't start with a leading slash.

Accessing properties file in a JSF application programmatically

I am trying to access the i18n properties file I'm using in my JSF application in code. (The idea is to have a page that displays its keys and values as a table actually.)
The project is a maven project, and in the src/resources/localization folder, and deployed in the war file in WEB-INF\classes\localization\
java.util.Properties prop = new java.util.Properties();
String path = "localization/stat_codes.properties";
InputStream foo = prop.getClass().getResourceAsStream(path);
But the variable foo turns out to be null whatever I set the path variable to, /WEB-INF/classes/localization/stat_codes.properties, "localization.stat_codes.properties" etc. A similar question is here, but there is no helpful answer there as well.
The Class#getResourceAsStream() can take a path which is relative to the location of the Class which you're using there as starting point. So, for example, if the class is located in the com.example package and you request the path foo/filename.properties, then it will actually load the com/example/foo/filename.properties file. But if you use /foo/filename.properties, then it will actually load foo/filename.properties from the classpath root.
So, your code
java.util.Properties prop = new java.util.Properties();
String path = "localization/stat_codes.properties";
InputStream foo = prop.getClass().getResourceAsStream(path);
will actually look for java/util/localization/stat_codes.properties file.
But in applications with a complex multiple classloader hierarchy, the one classloader isn't the other. The classloader which loaded the core Java classes does not necessarily have knowledge about files which are in the webapp's /WEB-INF/classes. So prefixing the path with / will not necessarily be the solution, it would still return null.
If you can guarantee that the current class is visible by the same classloader as the properties files (because they're in the same sub-root of the classpath, e.g. /WEB-INF/classes, then you should indeed use
String path = "/localization/stat_codes.properties";
InputStream foo = this.getClass().getResourceAsStream(path);
But if at some point, the properties files will be externalized because of more easy maintenance/editing during runtime so that you don't need to rebuild/redeploy/restart the webapp whenever you want to edit the files, then the above line of code will likely fail as well. The externalized location would be only accessible by a different classloader. The canonical solution is to use the thread's context classloader as starting point instead, it has access to all resources in the classpath.
String path = "localization/stat_codes.properties";
ClassLoader loader = Thread.currentThread().getContextClassLoader();
InputStream foo = loader.getResourceAsStream(path);
(note that this one cannot take a path starting with /, it's always relative to the common root)
See also:
Where to place and how to read configuration resource files in servlet based application?
ExternalContext#getResourceAsStream() returns null, where to place the resource file?
It seems that the culprit is the prop object, I supposed any object would work, but it has to be the current object (this) on which the method getClass() is invoked, it seems. Also, the path should start with a / since the localization directory resides in WEB-INF/classes.
String path = "localization/stat_codes.properties";
InputStream foo = this.getClass().getResourceAsStream(path);

Resources