Empty Context String Warning - java

I try to configure a jetty context (programmatically) for using a servlet serving the root context.
For the context path I set "/" and for the servlet mapping "/*". This works exactly the way I want it to but Jetty is complaining (warning) about the context path ending with '/'. When I set the context path to "" (empty string), it results in the warning about an empty string.
The documentation section of Jetty about this issue states:
Be aware
Java Servlet Specification 2.5 discourages an empty context path string, and Java Servlet Specification 3.0 effectively forbids it.
The portion of the Jetty source is:
public void setContextPath(String contextPath)
{
if (contextPath == null)
throw new IllegalArgumentException("null contextPath");
if (contextPath.endsWith("/*"))
{
LOG.warn(this+" contextPath ends with /*");
contextPath=contextPath.substring(0,contextPath.length()-2);
}
else if (contextPath.endsWith("/"))
{
LOG.warn(this+" contextPath ends with /");
contextPath=contextPath.substring(0,contextPath.length()-1);
}
if (contextPath.length()==0)
{
LOG.warn("Empty contextPath");
contextPath="/";
}
_contextPath = contextPath;
if (getServer() != null && (getServer().isStarting() || getServer().isStarted()))
{
Handler[] contextCollections = getServer().getChildHandlersByClass(ContextHandlerCollection.class);
for (int h = 0; contextCollections != null && h < contextCollections.length; h++)
((ContextHandlerCollection)contextCollections[h]).mapContexts();
}
}
So the question is, what context path should I set in order to map to the root of the context. Currently everything works fine but having a forbidden context path setting by specification or a Jetty warning, I guess I need something different.

The docs says that
The context path is the prefix of a URL path that is used to select
the context(s) to which an incoming request is passed. Typically a URL
in a Java servlet server is of the format
http://hostname.com/contextPath/servletPath/pathInfo, where each of
the path elements can be zero or more / separated elements. If there
is no context path, the context is referred to as the root context.
The root context must be configured as "/" but is reported as the
empty string by the servlet API getContextPath() method.
So, I guess you are fine using "/" .
http://www.eclipse.org/jetty/documentation/current/configuring-contexts.html

I tried to add a bug request for this after I noticed (thanks #Ozan!) that "/" is used in the case of setting the context path to "". So I thought it was a bug and yes it is. A bug report already exists for this issue and it was fixed in 9.0.6 which is available since 2013 Sep 30. So I just upgraded the jetty version and the warning is now gone.
The Jetty code now checks if the length of the path is greater 1:
public void setContextPath(String contextPath)
{
if (contextPath == null)
throw new IllegalArgumentException("null contextPath");
if (contextPath.endsWith("/*"))
{
LOG.warn(this+" contextPath ends with /*");
contextPath=contextPath.substring(0,contextPath.length()-2);
}
else if (contextPath.length()>1 && contextPath.endsWith("/"))
{
LOG.warn(this+" contextPath ends with /");
contextPath=contextPath.substring(0,contextPath.length()-1);
}
if (contextPath.length()==0)
{
LOG.warn("Empty contextPath");
contextPath="/";
}
_contextPath = contextPath;
if (getServer() != null && (getServer().isStarting() || getServer().isStarted()))
{
Handler[] contextCollections = getServer().getChildHandlersByClass(ContextHandlerCollection.class);
for (int h = 0; contextCollections != null && h < contextCollections.length; h++)
((ContextHandlerCollection)contextCollections[h]).mapContexts();
}
}

Related

Can't use "Handler" approach to adding a URLStreamHandler in AWS Lambda

I'm currently trying to add a URLStreamHandler so I can handle URLs with custom protocols. This works fine when run locally. When deployed to AWS Lambda I get:
java.net.MalformedURLException: unknown protocol: baas
I'm following the "Handler" approach to registering the URLStreamHandler.
I even went as far as copying the code from URL.getURLStreamHandler(String) and added logging into my own code that is run by Lambda:
(Note: this is from the Java 8 source - I realise now that this might not be representative because AWS Lambda uses a Java 11 runtime).
URLStreamHandler handler = null;
String packagePrefixList = null;
packagePrefixList
= java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction(
"java.protocol.handler.pkgs",""));
if (packagePrefixList != "") {
packagePrefixList += "|";
}
// REMIND: decide whether to allow the "null" class prefix
// or not.
packagePrefixList += "sun.net.www.protocol";
LOG.debug("packagePrefixList: " + packagePrefixList);
StringTokenizer packagePrefixIter =
new StringTokenizer(packagePrefixList, "|");
while (handler == null &&
packagePrefixIter.hasMoreTokens()) {
String packagePrefix =
packagePrefixIter.nextToken().trim();
try {
String clsName = packagePrefix + "." + "baas" +
".Handler";
Class<?> cls = null;
LOG.debug("Try " + clsName);
try {
cls = Class.forName(clsName);
} catch (ClassNotFoundException e) {
ClassLoader cl = ClassLoader.getSystemClassLoader();
if (cl != null) {
cls = cl.loadClass(clsName);
}
}
if (cls != null) {
LOG.debug("Instantiate " + clsName);
handler =
(URLStreamHandler)cls.newInstance();
}
} catch (Exception e) {
// any number of exceptions can get thrown here
LOG.debug(e);
}
}
This prints (in Cloudwatch logs):
packagePrefixList: com.elsten.bliss|sun.net.www.protocol (BaasDriver.java:94, thread main)
Try com.elsten.bliss.baas.Handler (BaasDriver.java:108, thread main)
Instantiate com.elsten.bliss.baas.Handler (BaasDriver.java:118, thread main)
com.elsten.bliss.baas.Handler constructor (Handler.java:55, thread main)
So, when run from my own code, in Lambda, it works.
However, the very next line of logging:
java.lang.IllegalArgumentException: URL is malformed: baas://folder: java.lang.RuntimeException
java.lang.RuntimeException: java.lang.IllegalArgumentException: URL is malformed: baas://folder
...
Caused by: java.net.MalformedURLException: unknown protocol: baas
at java.base/java.net.URL.<init>(Unknown Source)
at java.base/java.net.URL.<init>(Unknown Source)
at java.base/java.net.URL.<init>(Unknown Source)
So it seems odd the same code is failing when run in URL. The main difference I can think of is the parent classloader used to load URL and my code are different, and so there's some sort of class loading issue.
The SPI approach can't be used because Lambda doesn't extract META-INF folders!
Initially I thought the old URL.setURLStreamHandlerFactory(URLStreamHandlerFactory) approach was to be avoided, but it turns out this has been improved in recent Java versions, and so I have fallen back to that.
Specifically, a default fallback URLStreamHandlerFactory which is capable of handling streams to http, https, file et al is used as a fallback if the custom one provided cannot handle a stream.
This is a workaround though - it would be interesting to know why the class cannot be loaded.

HotSwapAgent failed to convert filePath to classPathPath

i am trying to use the HotSwapAgent in our Project.
We are using a Wildfly 10.x and our Project is deployed as an exploded EAR in which there is an exploded war.
I've added the following JVM-options:
-XXaltjvm=dcevm -javaagent:c:\dev\hotswap-agent.jar
When my WildFly is deploying i get the following Error:
HOTSWAP AGENT: 14:42:40.479 ERROR (org.hotswap.agent.plugin.spring.scanner.XmlBeanDefinationScannerAgent) - failed to convert filePath /C:/dev/projects/project_abc/abc/ABC/target/ABC_Exploded.ear/ABCWeb.war/WEB-INF/config/spring/soap-context.xml to classPath path
When i let the Wildfly run, later the following Error is shown and the Deployment fails.
rror creating bean with name 'systemConfigurationService' defined in ServletContext resource [/WEB-INF/config/spring/service-maintenance-context.xml]: Invocation of init method failed; nested exception is java.lang.reflect.UndeclaredThrowableException
Does anyone know how to configure this right ?
I've read that you can put an extraClassPath into the properties of the HotswapAgent but i've no clue what i should set.
You have to change the convertToClasspathURL in org.hotswap.agent.plugin.spring.scanner.XmlBeanDefinationScannerAgent in order to your needs.
Seems in your case above just the following to the method:
paths = filePath.split("WEB-INF/config/spring");
if (paths.length == 2) {
return paths[1];
}
convertToClasspathURL ( after modifying it for your classpath needs ) :
private static String convertToClasspathURL(String filePath) {
String[] paths = filePath.split("src/main/resources/");
if (paths.length == 2) {
return paths[1];
}
paths = filePath.split("WEB-INF/classes/");
if (paths.length == 2) {
return paths[1];
}
paths = filePath.split("target/classes/");
if (paths.length == 2) {
return paths[1];
}
paths = filePath.split("target/test-classes/");
if (paths.length == 2) {
return paths[1];
}
paths = filePath.split("WEB-INF/config/spring");
if (paths.length == 2) {
return paths[1];
}
LOGGER.error("failed to convert filePath {} to classPath path", filePath);
return filePath;
}
Hope it solves your problem!

Redisson: Not able to set address in SingleServer mode

I am using the single server mode to configure the redis server and port, am I missing something here ?
Config config = new Config();
config.useSingleServer().setAddress("localhost:6379");
But below exception is encountered
Exception in thread "main" java.lang.IllegalArgumentException: Illegal character in scheme name at index 0: [localhost]:6379
at java.net.URI.create(URI.java:852)
at org.redisson.misc.URIBuilder.create(URIBuilder.java:38)
at org.redisson.config.SingleServerConfig.setAddress(SingleServerConfig.java:129)
Seems the below code in org.redisson.misc.URIBuilder has issue
public static URI create(String uri) {
URI u = URI.create(uri);
// Let's assuming most of the time it is OK.
if (u.getHost() != null) {
return u;
}
String s = uri.substring(0, uri.lastIndexOf(":")).replaceFirst("redis://", "").replaceFirst("rediss://", "");
// Assuming this is an IPv6 format, other situations will be handled by
// Netty at a later stage.
return URI.create(uri.replace(s, "[" + s + "]"));
}
Managed to get it working by using the following configuration
Config config = new Config();
config.useSingleServer().setAddress("redis://localhost:6379");

Google drive rest API, Download files from root folder only

I am trying to download files in the root directory only. Currently I am not specifying any folders as I do not know how to so it downloads the most recent files that are in other folders that aren't the root. All I would like are the files in the root. The code that is getting the files and the download URLs is below:
public static void startDownload() throws IOException, ParseException {
Drive serv = getDriveService();
FileList result = serv.files().list().setMaxResults(10).execute(); //there are 10 files in the root folder
List<File> listA = result.getItems();
if (listA == null || listA.isEmpty()) {
System.out.println("No files found.");
} else {
System.out.println("Files:"+lista.size());
for (File file : listA) {
System.out.printf("%s (%s)\n", file.getTitle(), file.getDownloadUrl());
downloadFile(serv, file);
}
}
}
I would like to download all files in the root file only and not in any other folders. Any help would be appreciated.
You need to use the Q parameter to search
q string A query for filtering the file results. See the "Search for
Files" guide for supported syntax.
Sending something like the following will return everything that is not a folder with the parent of root.
mimeType != 'application/vnd.google-apps.folder' and 'root' in parents
There are a number of considerations.
Your line 3 needs to be
String q = "trashed = false and 'root' in parents and mimeType != 'application/vnd.google-apps.folder' "
FileList result = serv.files().list().setFields("*").setQ(q).setMaxResults(10).execute();
You need to be aware that this will return a maximum of 10 results, but even more so, you need to be aware that there is no minimum number of results. This means that if you have 11 files, you might get 10 in the first iteration and 1 in the 2nd. However, you could also get 1 and 10, or 3 and 6 and 2, or 0 and 0 and 1 and 10. You need to keep fetching results until the value of getNextPageToken() == null. So your line
if (listA == null || listA.isEmpty()) {
should be something like
if (result.getNextPageToken() == null) {
I realise that you've copy/pasted from the official documentation, but sadly that documentation is wrong.

Why does getRealPath() return null when deployed with a .war file? [duplicate]

This question already has answers here:
What does servletcontext.getRealPath("/") mean and when should I use it
(4 answers)
Closed 4 years ago.
getRealPath() is returning the actual path in the local system, but returns null when deployed with a .war file.
<%# page import="java.io.*" %>
<%# page contentType="text/html;charset=ISO-8859-1" %>
<%
int iLf = 10;
char cLf = (char)iLf;
String a= application.getResource("/");
//String myfile = application.getRealPath("/")+ "generate.xml";
//String myfile = request.getContextPath()+"generate.xml";
//String myfile = request.getRealPath("/")+"generate.xml";
out.println(myfile);
File outputFile = new File(myfile);
outputFile.createNewFile();
FileWriter outfile = new FileWriter(outputFile);
outfile.write(" <?xml version='1.0' encoding='UTF-8'?> "+cLf);
outfile.write(" <playlist version='1' xmlns = 'http://xspf.org/ns/0/' > " +cLf);
outfile.write(" <title>My Band Rocks Your Socks</title> "+cLf);
outfile.write("<trackList>"+cLf);
%>
<%! String[] sports; %>
<%
sports = request.getParameterValues("sports");
out.println("<html><body><h1>hello</h1></body></html>");
if (sports != null)
{
for (int i = 0; i < sports.length; i++)
{
// outfile.writeln (sports[i]);
String total=sports[i];
String[] sa=total.split("[,]");
// String[] sub=new String();
outfile.write("<track>"+cLf);
for (int j=0;j<sa.length;j++)
{
// outfile.writeln(sa[j]);
// outfile.writeln("sa["+j+"]="+sa[j]);
if( j == 0)
{
outfile.write("<location>" + sa[0] +"</location>"+cLf);
}
else if (j == 1)
{
outfile.write("<image>" + sa[1] +"</image>"+cLf);
}
else if( j==2)
{
outfile.write("<title>" + sa[2] +"</title>"+cLf);
}
}// end of inner for loop()
outfile.write("</track>"+cLf);
//outfile.writeln();
}// end of outer for()
}
//else outfile.writeln ("<b>none<b>");
outfile.write(" </trackList> "+cLf);
outfile.write(" </playlist> "+cLf);
outfile.close();
%>
<object type="application/x-shockwave-flash" width="400" height="170"
data="xspf_player.swf?playlist_url=generate.xml">
<param name="movie" value="xspf_player.swf?playlist_url=generate.xml" />
</object>
Can anyone provide me with an alternative for this?
It would be very helpful if you showed some sample code too.
For a start, ServletRequest.getRealPath(String path) is deprecated. The appropriate replacement is:
ServletContext context = session.getServletContext();
String realContextPath = context.getRealPath(request.getContextPath());
However, the API docs for ServletContext.getRealPath(String path) state:
"This method returns null if the servlet container cannot translate the virtual path to a real path for any reason (such as when the content is being made available from a .war archive)."
So the API is fulfilling its contract! However, all is not lost, as you can load a resource from the WAR using the following method, as defined in ServletContext:
ServletContext context = session.getServletContext();
InputStream is = context.getResourceAsStream("generate.xml");
Bit late, but I came across this question when I was having this issue in WebLogic. My solution was to add this to my weblogic.xml:
<?xml version='1.0' encoding='UTF-8'?>
<weblogic-web-app>
<container-descriptor>
<show-archived-real-path-enabled>true</show-archived-real-path-enabled>
</container-descriptor>
</weblogic-web-app>
I found this solution better for when you don't want to (or can't) edit the configuration on the WebLogic server.
do you use Weblogic?
If yes - then this is a Weblogic issue which you may fix in Weblogic admin console ->Domain->Web Applications - click the checkbox "Archived Real Path Enabled".
See: http://ananthkannan.blogspot.com/2009/12/servletcontextgetrealpath-returns-null.html
I had the same problems too. Calling getRealPath() return null when deployed to a standalone server. After searching around for a while, I found the solution for this, it's not in the code. It's in the config of your web server.
For me it's Weblogic 10.3, you go to Home - - Configuration - Web Application, set Archived Real Path Enabled to true. Restart server and everything works fine.
Hope this help,
Regards.
This solves the problem also:
weblogic.xml
<?xml version = '1.0' encoding = 'windows-1252'?>
<weblogic-web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.bea.com/ns/weblogic/weblogic-web-app http://www.bea.com/ns/weblogic/weblogic-web-app/1.0/weblogic-web-app.xsd" xmlns="http://www.bea.com/ns/weblogic/weblogic-web-app">
<container-descriptor>
<index-directory-enabled>true</index-directory-enabled>
<show-archived-real-path-enabled>true</show-archived-real-path-enabled>
</container-descriptor>
<virtual-directory-mapping>
<local-path>bla.war</local-path>
<url-pattern>*</url-pattern>
</virtual-directory-mapping>
<context-root>bla</context-root>
I do not believe it is possible to do what you're trying to do.
You should use getResource to read the xml file from inside your war file (this also works without war)
servletContext.getResourceAsStream("/generate.xml")
The leading slash depends on where the generate.xml is stored.
Take note context.getRealPath() can return null when there is user permission problem, check Web server running under which user.
if you want to write into
use
this.getClass().getResource("/").getPath();
to get the path
The following fix working fine for me.
// I am using Struts2
ServletContext sc = (ServletContext) ac.get(StrutsStatics.SERVLET_CONTEXT);
fileInputStream = sc.getResourceAsStream("test.xls");
After deployed war file, I am able to get the file from the context path.
The following fix my problem.
public EHWInit()
{
String resetRootPath = "";
try{
resetRootPath = this.getClass().getResource("/").getPath();
boolean isWinOS = System.getProperty("os.name").startsWith("Windows");
if( isWinOS )
{resetRootPath = resetRootPath.substring(1, resetRootPath.lastIndexOf("chucec"));}
else
{resetRootPath = resetRootPath.substring(0, resetRootPath.lastIndexOf("chucec"));}
resetRootPath = resetRootPath.replace("%20", " ");
System.out.println("EHWInit#75:resetRootPath=" + resetRootPath);
When you try to get getRealPath by this.getClass().getResource("/").getPath() when OS is Windows, then you may get a string like following:
EHWInit#73:getPath=/C:/Program%20Files%20(x86)/Apache%20Software%20Foundation/Tomcat%208.5/webapps/chucec/WEB-INF/classes/
Therefor, you need do some extra works on the returning string.Furthermore, if you want to get getRealPath by request. You can replace the code like follows:
public void resetSystemPath(HttpServletRequest paramHttpServletRequest)
{
//String str = paramHttpServletRequest.getRealPath("/");
HttpSession session = paramHttpServletRequest.getSession(true);
String str = session.getServletContext().getRealPath("/");
System.out.println("getRealPath:"+str);

Categories