I'm trying to deploy restSQL in my local tomcat installation based on this link.
From my tomcat webapps folder:
webapps\restsql-0.8\WEB-INF\classes\resources\properties
I have modified 'default-restsql.properties' to set the correct database connections
and retained the property 'sqlresources.dir=/resources/xml/sqlresources' while adding/creating the folder on that location.
I also modified in web.xml:
<context-param>
<param-name>org.restsql.properties</param-name>
<param-value>/WEB-INF/resources/properties/default-restsql.properties</param-value>
</context-param>
I'm quite sure that the default.restsql.properties is loaded since when I access this resource:
http://localhost:8080/restsql-0.8/conf
I get this response:
Properties loaded from /resources/properties/default-restsql.properties:
log4j.configuration = resources/properties/default-log4j.properties
org.restsql.security.Authorizer = org.restsql.security.impl.AuthorizerImpl
org.restsql.core.RequestLogger = org.restsql.core.impl.RequestLoggerImpl
**sqlresources.dir = /resources/xml/sqlresources**
database.driverClassName = com.mysql.jdbc.Driver
logging.config = resources/properties/default-log4j.properties
database.user = root
org.restsql.core.Factory.ResponseSerializerFactory = org.restsql.core.impl.ResponseSerializerFactoryImpl
org.restsql.core.SqlBuilder = org.restsql.core.impl.SqlBuilderImpl
database.password = root
org.restsql.core.Factory.ConnectionFactory = org.restsql.core.impl.ConnectionFactoryImpl
org.restsql.core.SqlResourceMetaData = org.restsql.core.impl.SqlResourceMetaDataMySql
org.restsql.core.HttpRequestAttributes = org.restsql.core.impl.HttpRequestAttributesImpl
logging.facility = log4j
response.useXmlSchema = false
org.restsql.core.Factory.RequestFactory = org.restsql.core.impl.RequestFactoryImpl
database.url = jdbc:mysql://localhost:3306/
logging.dir = /var/log/restsql
org.restsql.core.Factory.SqlResourceFactory = org.restsql.core.impl.SqlResourceFactoryImpl
request.useXmlSchema = false
response.useXmlDirective = false
org.restsql.core.Factory.RequestDeserializerFactory = org.restsql.core.impl.RequestDeserializerFactoryImpl
Properties using defaults:
org.restsql.core.Factory.Connection = org.restsql.core.impl.ConnectionFactoryImpl
java.util.logging.config.file = resources/properties/default-logging.properties
request.useXmlDirective = false
org.restsql.properties = /resources/properties/default-restsql.properties
However when I access this resources
http://localhost:8080/restsql-0.8/res/
I get this response:
SQL Resources directory /resources/xml/sqlresources does not exist ... please
correct your sqlresources.dir property in your restsql.properties file
Although the folder do exist: webapps\restsql-0.8\WEB-INF\classes\resources\xml\sqlresources
What could be the problem?
Sorry you're having trouble with deployment. restSQL requires an absolute path to the main properties file. It does not have the capability to search its WAR file or exploded web app dir, other than look in the classpath for the default.
Most paths are to other files, referenced in the main restSQL properties files have to be absolute. The only one that is relative is the logging.config. Please have a look at Deployment for all the nitty-gritty deployment instructions.
Hope that does the trick for you.
When it rains it pours?
Sounds like you had trouble running one of the database create scripts? Is that in restsql-sdk/WebContent/database/postgresql? Did you have errors running create-sakila.bat? Perhaps your psql executable is not in your path. You can edit the file to add it to your PATH environment variable temporarily.
You won't get any 5xx errors if the resource query returns no data. You will get a 200 with an empty readResponse document.
Your problem is likely a resource definition metadata issue. Is country_id from the country table? Is country defined as a table in the metadata? Can you post the resource definition?
Have you looked over the SQL resource rules at http://restsql.org/doc/SqlResourceRules.html? Sorry, SQL Functions and views are not allowed. You must use plain old columns and tables.
Related
I am trying to put mappings json files in a subdirectories due to different requirements based on diff profiles.
I have it working with default /mappings directory and all mappings work ok in postman.
WiremockConfiguration options = options()
.usingFilesUnderDirectory(System.getPtoperty(“user.dir”) + “/app/src/main/resources”
src/main/resources
-mappings
—folderA
—folderB
—folderC
But once I try to place json files under sub directory of “mappings” folder, no mappings get picked up and /__admin/mappings endpoint show a total of 0.
WiremockConfiguration options = options()
.usingFilesUnderDirectory(System.getPtoperty(“user.dir”) + “/app/src/main/resources**/mappings/aws**”
(Note the path difference)
I am just wondering if mappings folder subdirectories are even supported in wire mock or have I configured something incorrectly? It seems something too simple to be not supported by wiremock!
Many thanks
I have fixed it but for anyone facing similar problem u need to make “mappings” subdirectory of your custom folders.
src/main/resources
-my_wiremock_mappings
—folderA
—— mappings (should contain json files)
—folderB
—— mappings
—folderC
—— mappings
WiremockConfiguration options = options()
.usingFilesUnderDirectory(System.getPtoperty(“user.dir”) + “/app/src/main/resources/my_wiremock_mappings/folderA”
There is no need to add “mappings” to the path.
If you use a classpath ant pattern, you have to add *.json at the end.
#AutoConfigureWireMock(port = 8081, stubs = "classpath:/stubs/**/*.json")
https://github.com/spring-cloud/spring-cloud-contract/blob/main/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockConfiguration.java#L213
I'm trying to access my properties file in a war. The code is working, but when i'm exporting the code into a war and use a POST (with an accepted input) using Fiddler, it cannot find the config.properties. (NullPointerException)
The input and webservice are running correctly. Just trying to figure out a way to edit my properties while using a war.
Some facts:
I've made a RetreivePropertiesClass. This uses:
properties.load(this.getClass()
.getResourceAsStream("/WEB-INF/config.properties"));
My properties file path:
/com.webapp/WebContent/WEB-INF/config.properties
I'm trying to use the properties data in:
String url = RetreiveProperties.getUrl();
String driver = RetreiveProperties.getDriver();
String username = RetreiveProperties.getUsername();
String password = RetreiveProperties.getPassword();
// line below causes the NullPointerException
Class.forName(driver);
Getter used:
public static String getDriver() {
return driver = properties.getProperty("jdbc.driver");
}
When the war is deployed, the properties file is in:
webapps\com.webapp1\WEB-INF\config.properties
Config.properties:
jdbc.url = jdbc:postgresql://127.0.0.1:2222/gisdb
jdbc.driver = org.postgresql.Driver
jdbc.username = postgres
jdbc.password = admin
I already tried to work out the examples given here and here. Keeps giving the NullPointerException because the properties file isn't loaded.
Can anyone push me in the right direction?
Cheers!
If you are going to load the properties file from the classpath, it must be in the WEB-INF/classes directory inside of your war. (Or inside a jar inside of WEB-INF/lib ). The WEB-INF directory itself is not on the classpath.
If you make sure the file ends up as WEB-INF/classes/config.properties your above code should work if you change the getResourceAsStream call to getResourceAsStream("/config.properties")
If the method is a static method, the getClass() method will be failed, and prompts “Cannot make a static reference to the non-static method getClass() from the type Object“.
Instead, you should use CurrentClass.class.getClassLoader().getResourceAsStream.
Source: here
Having the following code broken deliberately to identify the source of a NullPointerException in something that should have been very simple but turns out to drive me nuts:
Properties properties = new Properties();
Thread currentThread = Thread.currentThread();
ClassLoader contextClassLoader = currentThread.getContextClassLoader();
InputStream propertiesStream = contextClassLoader.getResourceAsStream("resource.properties");
if (propertiesStream != null) {
properties.load(propertiesStream);
// TODO close the stream
} else {
// Properties file not found!
}
I get the "Properties file not found!" error, i.e. contextClassLoader.getResourceAsStream("resource.properties"); returns null.
This is a CXF-based client and I verified that the "resource.properties" file is in the current directory in which the client's jar resides (and runs).
I also verified the absolute path by including the following diagnostic code:
File file = new File("resource.properties");
System.out.println(file.getAbsolutePath());
The absolute path points to where the client's jar is.
I also tried finding out the context of the class loader, using:
System.out.println(Thread.currentThread().getContextClassLoader());
but instead some directory structure as demonstrated here, all I get is:
com.simontuffs.onejar.JarClassLoader#1decdec
Why would ClassLoader.getResourceAsStream() return null?
What am I missing?
I solved the mystery.
The key to solving was embedding some diagnostic logging when propertiesStream is null:
String classpath = System.getProperty("java.class.path");
LOG.info("CLASSPATH: " + classpath);
ClassLoader loader = MyClientMain.class.getClassLoader();
System.out.println("ClassLoader resource path: " + loader.getResource("resource.properties"));
So when I run with the original
contextClassLoader.getResourceAsStream("resource.properties")
I receive the null pointer condition, printing:
INFO: CLASSPATH: myproj.one-jar.jar
ClassLoader resource path: null
.
I then started suspecting something related to the "jar within a jar" as this is what the com.simontuffs.onejar essentially does (i.e. wrapping my project's jar inside a jar that contains all other library jars), so I opened myproj.one-jar.jar with 7-Zip and noted the full (absolute) path of "resource.properties":
myproj.one-jar.jar\main\myproj.jar\webapp\WEB-INF\classes\resource.properties
.
So I modified getResource("resource.properties") to:
getResource("/main/myproj.jar/webapp/WEB-INF/classes/resource.properties")
which didn't fix the problem but printed the following upon the null pointer condition:
INFO: CLASSPATH: myproj.one-jar.jar
ClassLoader resource path: jar:file:/myproj.one-jar.jar!/main/myproj.jar!//main/myproj.jar/webapp/WEB-INF/classes/resource.properties
.
Then... divine intervention fell upon me and I had the insight (not reading any documentation that could even hint this, I swear!) that I should be using this path instead:
getResource("/webapp/WEB-INF/classes/resource.properties")
And Voila! It works.
Whew.
As EJP pointed out, it means that the resource isn't available via the classpath for this particular classloader (different classloaders can have different classpaths).
Since the classloader is a JarClassLoader, it will only be able to load resources that are included inside the jar file. It won't see files that are in the same directory as the jar file.
Assume standard maven setup.
Say in your resources folder you have a file abc.
In Java, how can I get absolute path to the file please?
The proper way that actually works:
URL resource = YourClass.class.getResource("abc");
Paths.get(resource.toURI()).toFile();
It doesn't matter now where the file in the classpath physically is, it will be found as long as the resource is actually a file and not a JAR entry.
(The seemingly obvious new File(resource.getPath()) doesn't work for all paths! The path is still URL-encoded!)
You can use ClassLoader.getResource method to get the correct resource.
URL res = getClass().getClassLoader().getResource("abc.txt");
File file = Paths.get(res.toURI()).toFile();
String absolutePath = file.getAbsolutePath();
OR
Although this may not work all the time, a simpler solution -
You can create a File object and use getAbsolutePath method:
File file = new File("resources/abc.txt");
String absolutePath = file.getAbsolutePath();
You need to specifie path started from /
URL resource = YourClass.class.getResource("/abc");
Paths.get(resource.toURI()).toFile();
Create the classLoader instance of the class you need, then you can access the files or resources easily.
now you access path using getPath() method of that class.
ClassLoader classLoader = getClass().getClassLoader();
String path = classLoader.getResource("chromedriver.exe").getPath();
System.out.println(path);
There are two problems on our way to the absolute path:
The placement found will be not where the source files lie, but
where the class is saved. And the resource folder almost surely will lie somewhere in
the source folder of the project.
The same functions for retrieving the resource work differently if the class runs in a plugin or in a package directly in the workspace.
The following code will give us all useful paths:
URL localPackage = this.getClass().getResource("");
URL urlLoader = YourClassName.class.getProtectionDomain().getCodeSource().getLocation();
String localDir = localPackage.getPath();
String loaderDir = urlLoader.getPath();
System.out.printf("loaderDir = %s\n localDir = %s\n", loaderDir, localDir);
Here both functions that can be used for localization of the resource folder are researched. As for class, it can be got in either way, statically or dynamically.
If the project is not in the plugin, the code if run in JUnit, will print:
loaderDir = /C:.../ws/source.dir/target/test-classes/
localDir = /C:.../ws/source.dir/target/test-classes/package/
So, to get to src/rest/resources we should go up and down the file tree. Both methods can be used. Notice, we can't use getResource(resourceFolderName), for that folder is not in the target folder. Nobody puts resources in the created folders, I hope.
If the class is in the package that is in the plugin, the output of the same test will be:
loaderDir = /C:.../ws/plugin/bin/
localDir = /C:.../ws/plugin/bin/package/
So, again we should go up and down the folder tree.
The most interesting is the case when the package is launched in the plugin. As JUnit plugin test, for our example. The output is:
loaderDir = /C:.../ws/plugin/
localDir = /package/
Here we can get the absolute path only combining the results of both functions. And it is not enough. Between them we should put the local path of the place where the classes packages are, relatively to the plugin folder. Probably, you will have to insert something as src or src/test/resource here.
You can insert the code into yours and see the paths that you have.
To return a file or filepath
URL resource = YourClass.class.getResource("abc");
File file = Paths.get(resource.toURI()).toFile(); // return a file
String filepath = Paths.get(resource.toURI()).toFile().getAbsolutePath(); // return file path
I have a webapp which contains a manifest file, in which I write the current version of my application during an ant build task. The manifest file is created correctly, but when I try to read it in during runtime, I get some strange side-effects. My code for reading in the manifest is something like this:
InputStream manifestStream = Thread.currentThread()
.getContextClassLoader()
.getResourceAsStream("META-INFFFF/MANIFEST.MF");
try {
Manifest manifest = new Manifest(manifestStream);
Attributes attributes = manifest.getMainAttributes();
String impVersion = attributes.getValue("Implementation-Version");
mVersionString = impVersion;
}
catch(IOException ex) {
logger.warn("Error while reading version: " + ex.getMessage());
}
When I attach eclipse to tomcat, I see that the above code works, but it seems to get a different manifest file than the one I expected, which I can tell because the ant version and build timestamp are both different. Then, I put "META-INFFFF" in there, and the above code still works! This means that I'm reading some other manifest, not mine. I also tried
this.getClass().getClassLoader().getResourceAsStream(...)
But the result was the same. What's the proper way to read the manifest file from inside of a webapp running in tomcat?
Edit: Thanks for the suggestions so far. Also, I should note that I am running tomcat standalone; I launch it from the command line, and then attach to the running instance in Eclipse's debugger. That shouldn't make a difference, should it?
Maybe your side-effects come from the fact that almost all jars include a MANIFEST.MF and you're not getting the right one. To read the MANIFEST.MF from the webapp, I would say:
ServletContext application = getServletConfig().getServletContext();
InputStream inputStream = application.getResourceAsStream("/META-INF/MANIFEST.MF");
Manifest manifest = new Manifest(inputStream);
Please note that running Tomcat from Eclipse is not the same as running Tomcat alone as Eclipse plays with the classloader.
a bit late, but this works for me (web appl in Glassfish)
Properties prop = new Properties();
prop.load(getServletContext().getResourceAsStream("/META-INF/MANIFEST.MF"));
System.out.println("All attributes:" + prop.stringPropertyNames());
System.out.println(prop.getProperty("{whatever attribute you want}"));
Try to use jcabi-manifests, that does all this loading work for you. For example:
String version = Manifests.read("My-Version");
loads My-Version attribute from one of available MANIFEST.MF files.
Important to mention that (more details are here) in most web containers current thread class loader is not the same as servlet context class loader. That's why you should append your servlet context to the register in runtime (more info):
Manifests.append(servletContext);
Also, check this out: http://www.yegor256.com/2014/07/03/how-to-read-manifest-mf.html
The default way class loaders work is to defer to the parent before attempting to lookup their own resources. So if a parent class loader has any manifest available, that's what you'll get. In fact, app servers don't necessarily do this, to allow applications to override versions of libraries. Further, class loaders can have multiple jars and hence multiple manifests.
It may be able to get a resource URL of one of your uniquely named resource. Open a connection. Cast to JarURLConnection. Get the JarFile. Load the manifest from that. That may not work, particularly if Tomcat explodes the war.
[Update] Of course, the war file itself isn't on the classpath. The classpath will have something like WEB-INF/lib/(.jar|.zip) and WEB-INF/classes/. Getting a resource from the ServletContext should work.
Best solution: Do something different. :)
The right manifest exists in application root at server.
Find out the appication root, for instance by finding out classpath of your class:
String rootPath = getClass().getProtectionDomain().getCodeSource().getLocation().getPath()
Then replace the path above with the founded path: Glassfish example:
/applications/<webProject>/META-INF/MANIFEST.MF
It work for me.
Don't know about a "official" way to read it, but if the MANIFEST.MF can't be properly loaded as a resource, how about trying to derive its path from a "ServletContext.getRealPath()" on some web path defined in your app?
Writing the app version also to some else place (a property file in WEB-INF/classes) by ant during build is another solution that comes to my mind.
This is what I do to print various versions to a logfile. I have hardcoded an expanded path but apps may use servletContext.getRealPath("/") to read a full path to webapp folder. May print just given libraries or everything from lib folder.
// print library versions (jersey-common.jar, jackson-core-2.6.1.jar)
try {
List<String> jars = Arrays.asList( "jersey-common", "jackson-core", "openjpa", "mylib" );
StringBuilder verbuf = new StringBuilder();
for(File file : new File("/opt/tomcat/webapps/myapp/WEB-INF/lib/").listFiles() ) {
String name = file.getName();
if (file.isDirectory() || !file.isFile() || !name.endsWith(".jar") ) continue;
name = name.substring(0, name.length()-4);
boolean found = jars.contains(name);
if (!found) {
int idx = name.lastIndexOf('-');
if (idx>0)
found = jars.contains( name.substring(0, idx) );
}
if (!found) continue;
JarFile jarFile = new JarFile(file, false);
try {
String ver;
Manifest mf = jarFile.getManifest();
if (mf!=null) {
ver = mf.getMainAttributes().getValue("Bundle-Version");
if (ver==null || ver.isEmpty())
ver = mf.getMainAttributes().getValue("Implementation-Version");
} else ver=null;
if (verbuf.length()>0) verbuf.append(", ");
verbuf.append(name + "=" + (ver!=null?ver:"") );
} finally {
jarFile.close();
}
}
System.out.println( verbuf.toString() );
} catch(Exception ex) {
ex.printStackTrace();
}