How to remove .py from urls for pyservlet using jython - java

I'm looking at the jython servlet tutorial and have got everything working. How do I make the url be
localhost:8080/jythondemo/JythonServlet1
instead of
localhost:8080/jythondemo/JythonServlet1.py
http://seanmcgrath.blogspot.com/JythonWebAppTutorialPart1.html
Here is the relevant part from web.xml
<web-app>
<servlet>
<servlet-name>ServletTest</servlet-name>
<servlet-class>ServletTest</servlet-class>
</servlet>
<servlet>
<servlet-name>PyServlet</servlet-name>
<servlet-class>org.python.util.PyServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ServletTest</servlet-name>
<url-pattern>/ServletTest</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>PyServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
I've also tried with
<servlet-mapping>
<servlet-name>PyServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
It seems with the above changes pyservlet is getting the url JythonServlet1 but it does not know what to do with it. Here is the error message:
javax.servlet.ServletException: I can't guess the name of the class from /.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/testjython3/JythonServlet1
org.python.util.PyServlet.createInstance(PyServlet.java:202)
org.python.util.PyServlet.loadServlet(PyServlet.java:188)
org.python.util.PyServlet.getServlet(PyServlet.java:178)
org.python.util.PyServlet.service(PyServlet.java:155)

As noted by #Jigar there's a restriction in the actual Jython Servlet code. However, you may get around that issue by creating a simple URL translator. It consists in a Servlet that internally forwards the request to the Py Servlet.
Use the following code for web.xml:
<web-app>
<servlet>
<servlet-name>AliasServlet</servlet-name>
<servlet-class>juanal.AliasServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>PyServlet</servlet-name>
<servlet-class>org.python.util.PyServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>AliasServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>PyServlet</servlet-name>
<url-pattern>*.py</url-pattern>
</servlet-mapping>
</web-app>
Create a new class, say, juanal.AliasServlet, with the following content:
package juanal;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class AliasServlet extends HttpServlet
{
#Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
String URI = request.getRequestURI();
String newURI = URI + ".py";
getServletConfig().getServletContext().getRequestDispatcher(newURI).forward(request, response);
}
}
So, for a URL like this: localhost:8080/jythondemo/JythonServlet1, it will internally forward the request to JythonServlet1.py

Try this
<url-pattern>/*</url-pattern>
After that every request will be served by PyServlet

It looks like the problem is inherent to PyServlet.java. PyServlet uses regular expressions to find the name of the Python class to load based on the path of the request. The regular expression used is defined as follows (line 245 in my copy of the source):
private static final Pattern FIND_NAME = Pattern.compile("([^/]+)\\.py$");
Unfortunately, this regular expression will break if the input URL path doesn't contain a ".py" extension - this raises the error that you saw. From line 200:
Matcher m = FIND_NAME.matcher(file.getName());
if (!m.find()) {
throw new ServletException("I can't guess the name of the class from "
+ file.getAbsolutePath());
}
Since FIND_NAME is defined as private and final, I don't see a good way to override this behavior by just subclassing PyServlet - I think you'll have to make a copy of PyServlet and redefine this behavior in a fresh class.

I'm new to python. But if you have Apache, you could rewrite all .py URLs!

Just for the record: #Juanal AliasServlet trick works nicely.
I just had to use request.getServletPath() instead of getRequestURI().
(working with Eclipse)

Related

#PathVariable is not working in spring

I have PersonController as below :
#Controller
#RequestMapping("person")
public class PersonController {
#RequestMapping(value= "/{personId}", method = RequestMethod.GET, produces={"application/json"})
public #ResponseBody Map<String, Object> getPerson(#PathVariable("personId") Integer personId) {
// code to get person
}
Tomcat starts up fine, I see this in the console :
Mapped "{[/person/{personId}],methods=[GET],params=[],headers=[] ,consumes=[],produces=[application/json],custom=[]}" onto public java.util.Map<java.lang.String, java.lang.Object> com.test.web.controller.PersonController.getPerson(java.lang.Integer)
But if I hit the url http://localhost:8080/sample/person/1 I get
HTTP Status 404 - /sample/person/1
In the web.xml
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/servlet-context.xml</param-value>
</init-param-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/sample/*</url-pattern>
</servlet-mapping>
I copy/pasted your PersonController class and it worked fine here.
So I did check your web.xml and your app servlet is mapping the pattern "/sample/*".
If I am corret, I suspect your project is called "sample" in Eclipse. In that case, you have to access your site as follows:
http://localhost:8080/sample/sample/person/1
The mapping in your web.xml will always start from your root context, and that is why you are getting 404 error.
If you want to access your controller from the root domain (in this case it is your actual Eclipse project name by default, but it can be configured too) you can use your servlet mapping as follows:
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
I recommend that you use /rest/* or other mark since it will scale better for other types of content.
Let me know if it worked.

Getting null error when running a simple JAX-RS app on Websphere Application Server 7

I have no compilation errors and my app launches fine on my testing server. However, I get an error when trying a GET request:
[1/2/14 10:23:13:248 EST] 00000022 RequestProces I org.apache.wink.server.internal.RequestProcessor logException The following error occurred during the invocation of the handlers chain: WebApplicationException (404 - Not Found) with message 'null' while processing GET request sent to http://localhost:9081/IDMWorkflowServices/resources/workflow
Here is my web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name>IDMWorkflowServices</display-name>
<servlet>
<description>
JAX-RS Tools Generated - Do not modify</description>
<servlet-name>JAX-RS Servlet</servlet-name>
<servlet-class>com.ibm.websphere.jaxrs.server.IBMRestServlet</servlet-class>
<init-param>
<param-name>javax.ws.rs.core.Application</param-name>
<param-value>com.psg.itim.workflow.WorkflowResourceApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>JAX-RS Servlet</servlet-name>
<url-pattern>
/resources/*</url-pattern>
</servlet-mapping>
</web-app>
Here is WorkflowResource:
import javax.ws.rs.GET;
import javax.ws.rs.Produces;
import javax.ws.rs.Path;
// The Java class will be hosted at the URI path "/workflow"
#Path("/workflow")
public class WorkflowResource {
#GET
#Produces("text/plain")
public String getClichedMessage() {
// Return some cliched textual content
return "Hello World";
}
}
Here is WorflowResourceApplication:
import javax.ws.rs.core.Application;
import java.util.HashSet;
import java.util.Set;
public class WorkflowResourceApplication extends Application{
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<Class<?>>();
classes.add(WorkflowResource.class);
return classes;
}
}
If it's not painfully obvious, this is my first attempt using JAX-RS. I'm not exactly sure what I do or do not need from the above code to get this to work. It seems simple, but when I go to this url
http://localhost:9081/IDMWorkflowServices/resources/workflow
the 404 happens. Any ideas of what I am doing wrong?
Resolved! The only thing that was wrong was this line:
<param-name>javax.ws.rs.core.Application</param-name>
I changed it to:
<param-name>javax.ws.rs.Application</param-name>
I assumed it should have been the same Class I was calling from WorflowResourceApplication.java, but this was not the case. Everything works fine now. Apparently the application recognized the class error as a client side issue and registered a 404.
The first step to debug this would be to see if you have the correct port. So do this
- Try accessing just - http: //localhost:9081 . see if you get to default page or blank page or hello page if there is default index.jsp. If you get 404 then that means that you serever is running but your port number is incorrect.
If you are unsure what your port settings are(If I am correct then default port should be 9080) then follow this documentation - http://pic.dhe.ibm.com/infocenter/wasinfo/v7r0/index.jsp?topic=%2Fcom.ibm.websphere.migration.nd.doc%2Finfo%2Fae%2Fae%2Frmig_portnumber.html

servlet error The requested resource () is not available [duplicate]

This question already has answers here:
Servlet returns "HTTP Status 404 The requested resource (/servlet) is not available"
(19 answers)
Closed 6 years ago.
I am new to servlets .I am using eclipse juno for this.I am having a trouble in running my program..My code is
package sTraining;
import java.io.*;
import javax.servlet.*;
public class Servlet1 implements Servlet{
ServletConfig config=null;
public void init(ServletConfig config){
this.config=config;
System.out.println("servlet is initialized");
}
public void service(ServletRequest req,ServletResponse res)
throws IOException,ServletException{
res.setContentType("text/html");
PrintWriter out=res.getWriter();
out.print("<html><body>");
out.print("<b>hello simple servlet</b>");
out.print("</body></html>");
}
public void destroy(){System.out.println("servlet is destroyed");}
public ServletConfig getServletConfig(){return config;}
public String getServletInfo(){return "copyright 2007-1010";}
}
I am getting this error[http://localhost:8080/Test/WEB-INF/classes/sTraining/Servlet1.java][1]
although i have this thing in my web .xml file
<servlet>
<description></description>
<display-name>Servlet1</display-name>
<servlet-name>Servlet1</servlet-name>
<servlet-class>servlet.Servlet1</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Servlet1</servlet-name>
<url-pattern>/Servlet1</url-pattern>
</servlet-mapping>
why this is not running? My code is fine. First time when I run this page it run, but running this program after my second program it did not run and that second program also not run.
Why are you accessing
http://localhost:8080/Test/WEB-INF/classes/sTraining/Servlet1.java
? You should be accessing
http://localhost:8080/Test/Servlet1
Read the above as
[protocol or scheme] :// [host] : [port] / [context] / [servlet mapping]
Also, according to the source code you've posted. The Servlet1 class is in package sTraining. Your web.xml should therefore have
<servlet>
<description></description>
<display-name>Servlet1</display-name>
<servlet-name>Servlet1</servlet-name>
<servlet-class>sTraining.Servlet1</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Servlet1</servlet-name>
<url-pattern>/Servlet1</url-pattern>
</servlet-mapping>
A Servlet Container will not make anything in the WEB-INF folder available to client requests.
What you are doing is not great practice. Your class should probably extend HttpServlet to get some standard HTTP behavior. You also shouldn't be writing HTML in Java code. Try reading the tutorial and references we have on Stackoverflow, here.
Put ./Servlet1 in your form action attribute
<form action="./Servlet1">
....
</form>
and check your web.xml
your package name is different
<servlet>
<description></description>
<display-name>Servlet1</display-name>
<servlet-name>Servlet1</servlet-name>
<servlet-class>sTraining.Servlet1</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Servlet1</servlet-name>
<url-pattern>/Servlet1</url-pattern>
</servlet-mapping>

Adding multiple servlets in single web.xml

I am trying to run two Servlet-class in a single web.xml but its not working, each servlet-class works fine independently.
web.xml:
<servlet>
<servlet-name>spring-ws</servlet-name>
<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
<init-param>
<param-name>transformWsdlLocations</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring-ws</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>240</session-timeout>
</session-config>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-ws-servlet.xml
/WEB-INF/health-page-servlet.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>health-page</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>health-page</servlet-name>
<url-pattern>/health.htm</url-pattern>
</servlet-mapping>
Do let me know if you can figure something wrong that i am doing.
I tried the below link but it doesnt work for me
Can I use Spring MVC and Spring WS in one single application?
This isn't going to work. The one which is mapped on /* overtakes all requests. You need to map it on / instead so that it will only intercept on requests which are not matched by all other existing servlets (including the JSP servlet which is implicitly mapped on *.jsp and all "normal" static resources like CSS/JS/image files!). See also Difference between / and /* in servlet mapping url pattern.
If being able to serve static resources is also required, then better map it on a more specific URL pattern like /ws/* and create a Filter which checks the request URI and then forwards accordingly. That filter can in turn safely be mapped on /*. See also this answer for a more concrete code example: How to access static resources when mapping a global front controller servlet on /*.
I am using Java configuration in my project and following code works fine for the same purpose:
public class Initializer implements WebApplicationInitializer {
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(ApplicationConfiguration.class);
ctx.setServletContext(servletContext);
MessageDispatcherServlet messageDispatcherServlet = new MessageDispatcherServlet();
messageDispatcherServlet.setApplicationContext(ctx);
messageDispatcherServlet.setTransformWsdlLocations(true);
Dynamic dynamic = servletContext.addServlet("messageDispatcherServlet", messageDispatcherServlet);
dynamic.addMapping("/ws/*");
dynamic.setLoadOnStartup(1);
dynamic = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
dynamic.addMapping("/");
dynamic.setLoadOnStartup(1);
}
}
you have a mapping for /* in the spring-ws section which is getting the request. you need to
come up with a different strategy... Try putting the /health.htm before the /* mapping.

How to allow access to static content when having default servlet

I map all requests to /* to a specific servlet.
My static content is hidden by this configuration.
How can i allow access to specific files (such as crossdomain.xml)?
When you map /* to a specific servlet, all requests will be forwarded to that servlet, unless you provide a more explicit mapping to another servlet.
That is, if you have /* mapped to ServletA, and /static/* mapped to ServletB, then following Servlets will get called.
http://localhost:8080/abc.jpg -> ServletA
http://localhost:8080/static/abc.jpg -> ServletB
http://localhost:8080/xyz/abc.jpg -> ServletA
So one option you have is to write a Servlet to handle the static content, which will grab the file and return it as response. You can map that servlet to a prefixed by something like /static/*. This requires that all URL references to your static files to be updated to contain this '/static' part.
If that is not feasible for you, then probably you can use the same servlet, but mapped to multiple URL patterns (probably by extension) as follows.
<servlet>
<servlet-name>static-servlet</servlet-name>
<servlet-class>xxx.yyy.StaticServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>static-servlet</servlet-name>
<url-pattern>*.xml</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>static-servlet</servlet-name>
<url-pattern>*.jpg</url-pattern>
</servlet-mapping>
If you want this to be fine-grained to the level of each file, you can map the servlet to your file URL as well.
Cookbook:
Map your controller Servlet on a more specific url-pattern like /app/*.
Put all the static content in a specific folder like /static.
Create a Filter which is mapped on /* which transparently continues the chain for any /static requests and dispatches other requests to /app.
So, in a nutshell:
<filter>
<filter-name>filter</filter-name>
<filter-class>com.example.Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>controller</servlet-name>
<servlet-class>com.example.Controller</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>controller</servlet-name>
<url-pattern>/pages/*</url-pattern>
</servlet-mapping>
with the following in filter's doFilter():
String uri = ((HttpServletRequest) request).getRequestURI();
if (uri.startsWith("/static/")) {
chain.doFilter(request, response); // Goes to default servlet.
} else {
request.getRequestDispatcher("/app" + uri).forward(request, response);
}
No, you do not end up with extra /app path in the URL. It's fully transparent. Make if necessary "/static" and/or "/app" an <init-param> of the filter.
And one more(a direct) servlet mapping like this<servlet-mapping><servlet-name>StaticContentServlet</servlet-name><url-pattern>/crossdomain.xml</url-pattern></servlet-mapping>
probably you can put your static content under different URL like /static/* and then map this URL to a Servlet which responds with the static content.

Categories

Resources