#WebServlet Annotation and servlet-mapping differences - web-services

In my servlet class, I have annotated the class with:
#WebServlet("/OnlinePostListener/testFromAnnotation")
public class OnlinePostListener extends HttpServlet {
...
}
My web.xml contains the following:
<servlet>
<description>
</description>
<display-name>OnlinePostListener</display-name>
<servlet-name>OnlinePostListener</servlet-name>
<servlet-class>com.me.forwardingProxy.OnlinePostListener</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>OnlinePostListener</servlet-name>
<url-pattern>/testFromWebXML</url-pattern>
</servlet-mapping>
My servlet only responds when I access the URL:
http://localhost:8080/forwardingProxy/OnlinePostListener/testFromAnnotation
but not:
http://localhost:8080/forwardingProxy/OnlinePostListener/testFromWebXML
What is the difference between the #WebServlet's annotation and servlet-mapping?
Why is the servlet-mapping not working for this URL-pattern?

Because the Servlet specification requires that mappings defined in web.xml override rather than add to those defined in annotations. The reason is that without this, there would be no way to disable a mapping defined in an annotation.

It's because you are using wrong url to fetch the servlet in the later case.
Use the correct url :
http://localhost:8080/forwardingProxy/testFromWebXML
ERROR : You used an extra /OnlinePostListener in later case.
In the first case your mapped URL for the specified servlet is "/OnlinePostListener/testFromAnnotation" hence you have used this string as appending URL to http://localhost:8080/forwardingProxy BUT in the later case you have mapped the servlet to /testFromWebXML ( AND NOT /OnlinePostListener/testFromWebXML).
If,however, you insist on using the URL http://localhost:8080/forwardingProxy/OnlinePostListener/testFromWebXML to exploit web.xml you should make following changes :
<servlet-mapping>
<servlet-name>OnlinePostListener</servlet-name>
<url-pattern>/OnlinePostListener/testFromWebXML</url-pattern>
</servlet-mapping>

Related

Dynamic URI based on file name/cfg file/property name

I am trying to pass a to URI value dynamically with a property value. That property value will be configured already in the cfg file.
When the file name is extracted using CamelFileNameOnly header, it has to get passed to the to Uri endpoint. So that the same name is referred in the code.
Please find my code below:
I have dropped a file with name KevinFile.txt in my server location= D:\Servers\jboss-fuse-6.2.0.redhat-133\data\myLocalFTP (file://data/myLocalFTP)
Config File
local.folder.url=file://data/myLocalFTP
KevinFile=file://data/KevinFileDirectory
Camel Route
<route id="awsRoute">
<from uri="{{local.folder.url}}"/>
<bean ref="processorClass" method="process"/>
<log message="myProperty value is ${exchangeProperty.myProperty}"/> <---Gives the fileName
<to uri="{{${exchangeProperty.myProperty}}}"/> <--This is the spot i am getting error :(
</route>
ProcessorClass.java
public class ProcessorClass implements Processor{
#Override
public void process(Exchange exchange) throws Exception {
String fileName = (String) exchange.getIn().getHeader("CamelFileNameOnly");
exchange.setProperty("myPropertyNew", fileName);
}
}
If I understand correctly, you need to specify "dynamic" vlue for the constant part of the producer. Instead of <to uri="{{${exchangeProperty.myProperty}}}"/> you can use recipientList or routingSlip:
<recipientList>
<simple>${exchangeProperty.myProperty}</simple>
</recipientList>
or
<routingSlip>
<simple>${exchangeProperty.myProperty}</simple>
</routingSlip>
Ah what your looking for is simply setting the header as a property. You can do that like this:
from("direct:start")
.setHeader("CamelFileNameOnly").simple("{{myPropertyName}}")
.to("file://data/myLocalDisk");
You can also simplify this by using the uri syntax available on the file component in this case (Thanks to Sergii for the recommendation). Just make sure you check the camel documentation for each component certain components rely on exchange headers, while others can leverage URI properties.
from("direct:start")
.to("file://data/myLocalDisk?fileName={{myPropertyName}}");
Its also worth noting that if you have logic that you want to use before setting the header you can have the setHeader call a bean.
from("direct:start")
.setHeader("CamelFileNameOnly").bean(MyPropertyLogicBean.class, "someMethod({{myPropertyName}})")
.to("file://data/myLocalDisk");
Use the camel properties component to get this property to resolve.
Reference: http://camel.apache.org/properties.html

Jetty 9.3.5 ProxyServlet RewriteTarget Method and !asyncSupported

I am using Jetty version 9.3.5 to create ProxyServlet.
To do so, I am extending my class from
org.eclipse.jetty.proxy.ProxyServlet;
Unlike previous version, I do not get the method protected URI rewriteURI(HttpServletRequest request) to override. After reading through grepcode I am seeing something like the followings and used it:
#Override
protected String rewriteTarget(HttpServletRequest request) {
if (!validateDestination(request.getServerName(), request.getServerPort()))
return null;
String roleAlias = (String)request.getSession().getAttribute(ATTR_PROXY_ROLE_ALIAS);
String uri =request.getRequestURI();
String aliasedURI = getAliasedURI(request.getMethod(), uri, roleAlias);
return aliasedURI ;
}
I do not know if this is the correct method to override.
In web.xml I have few filters and this servlet defined. For Servlet I have defined like this:
<servlet>
<servlet-name>Proxy</servlet-name>
<servlet-class>com.company.MyProxyServlet</servlet-class>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>Proxy</servlet-name>
<url-pattern>/proxy/*</url-pattern>
</servlet-mapping>
But I get the following exception? Any idea? Do I need to do same thing for the filters? then how? or what else missing?
java.lang.IllegalStateException: !asyncSupported
at org.eclipse.jetty.server.Request.startAsync(Request.java:2224)
at org.eclipse.jetty.proxy.ProxyServlet.service(ProxyServlet.java:80)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at com.company.MyProxyServlet.service(MyProxyServlet.java:66)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:821)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1685)
at com.netiq.sentinel.elasticsearch.proxy.AuditFilter.doFilter(AuditFilter.java:104)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1668)
at com.netiq.sentinel.elasticsearch.proxy.SecurityFilter.doFilter(SecurityFilter.java:160)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1668)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:581)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:226)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1158)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:511)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1090)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:213)
at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:109)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:119)
at org.eclipse.jetty.server.Server.handle(Server.java:517)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:306)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:242)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:261)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:95)
at org.eclipse.jetty.io.ssl.SslConnection.onFillable(SslConnection.java:192)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:261)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:95)
at org.eclipse.jetty.io.SelectChannelEndPoint$2.run(SelectChannelEndPoint.java:75)
at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.produceAndRun(ExecuteProduceConsume.java:213)
at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.run(ExecuteProduceConsume.java:147)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:654)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:572)
Any Help?
Note:- I found few other post related to this error but nowhere the rewriteTarget method is used. Everywhere rewriteURI is used and I do not find it with Jetty 9.3.5.
Please Help.
I found the solution.
We need to add <async-supported>true</async-supported> for all the filters also.
For embedded jetty on version 9.3.7, here is how you can register an AsyncProxyServlet:
ServletHandler proxyHandler = new ServletHandler();
AsyncProxyServlet servlet = ...your instance of a proxy...;
ServletHolder proxyServletHolder = new ServletHolder(servlet);
proxyServletHolder.setAsyncSupported(true);
proxyServletHolder.setInitParameter("maxThreads", "100");
proxyHandler.addServletWithMapping(proxyServletHolder, "/*");
That handler can be added to a HandlerList etc.

Magento's Observer event isn't working and using webservices inside a Observer class

I'm trying to create a dynamic product discount using values from a webservice.
I've searched some guides on the internet about this matter and I found that I needed to use checkout_cart_product_add_after and checkout_cart_update_items_after.
However, I followed some guides. Created my own module (which is visible in Magento back office: Configuration > Advanced > Modules) and a observer for this module. I didn't create anything more but it's not working. Since I can see the module in that menu, I believe the problem is on the observer/event call.
Here is the config.xml (which is inside app\code\local\namespace\MyModule\etc) for my module:
<?xml version="1.0" encoding="UTF-8"?>
<config>
<modules>
<namespace_MyModule>
<version>0.1.0</version>
</namespace_MyModule>
</modules>
<global>
<events>
<checkout_cart_product_add_after>
<observers>
<namespace_MyModule_Discount>
<class>MyModule/Observer</class>
<method>MyModulePriceChange</method>
</namespace_MyModule_Discount>
</observers>
</checkout_cart_product_add_after>
</events>
</global>
</config>
And this is my Observer (which is inside app\code\local\namespace\MyModule\Model) for my module:
<?php
class namespace_MyModule_Model_Observer
{
public function MyModulePriceChange(Varien_Event_Observer $obs)
{
// Get the quote item
$item = $obs->getQuoteItem();
// Ensure we have the parent item, if it has one
$item = ( $item->getParentItem() ? $item->getParentItem() : $item );
// Load the custom price
$price = $this->_getPriceByItem($item);
// Set the custom price
$item->setCustomPrice($price);
$item->setOriginalCustomPrice($price);
// Enable super mode on the product.
$item->getProduct()->setIsSuperMode(true);
}
protected function _getPriceByItem(Mage_Sales_Model_Quote_Item $item)
{
$price = 4;
//use $item to determine your custom price.
return $price;
}
}
?>
Also, is it possible do call soap client to use a webservice inside a observer?
I hope my question is clear, thank you in advance for helping.
I see some issues with your config.xml. First of all, use capitalized both company name and module name. namespace_MyModule will become your namespace.
You have to declare models under global section like this:
<models>
<mycompany_mymodule>
<class>Mycompany_Mymodule_Model</class>
</mycompany_mymodule>
</models>
This will tell magento you want to use mycompany_mymodule for models in your module, and class name of each module will start with Mycompany_Mymodule_Model.
Where Mycompany and Mymodule are respective to folders of your module: app/code/local/Mycompany/Mymodule.
The modules section of config.xml should also have this namespace (Mycompany_Mymodule), matching name of your file app/etc/modules and folder structure in app/code/local.
The observers then become the following (I added type, and changed class):
<observers>
<namespace_MyModule_Discount>
<type>singleton</type>
<class>mycompany_mymodule/Observer</class>
<method>MyModulePriceChange</method>
</namespace_MyModule_Discount>
</observers>
Then try to test your observer method by adding there some code like die("message").
You haven't declared the models tag in the config.xml file.
An observer is a model after all and magento will not know where to find it (that MyModule/Observer you reference). Below it's an example of declaring models tag:
<models>
<MyModule>
<class>Namespace_Modulename_Model</class>
</MyModule>
</models>
Yes, you can do soap api calls inside observer.

restful service interface with jersey

Can I create a restful service with interface and implementation class?
If so, will all JAX-RS related imports go into the interface?
I am using jersey2.4 and jetty8.1.
Here is my MyService interface:
package foo.bar;
#Path("/abc")
public interface MyService {
#GET
#JSONP
#Path("/method/{id}")
public MyResponse getStuff(#PathParam("id") Integer id);
}
And an implementation of MyServiceImpl that interface
package foo.bar.impl;
public class MyServiceImpl implements MyService {
public MyServiceImpl() {}
#Override
public MyResponse getStuff(Integer id) {
// do stuff
return MyResponse;
}
}
Here's the web.xml file:
<servlet>
<servlet-name>Scivantage REST Service</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>foo.bar</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
I registered this service provider package (foo.bar) but it complains saying this
javax.servlet.ServletException: A MultiException has 1 exceptions. They are:|1. java.lang.NoSuchMethodException: Could not find a suitable constructor in foo.bar.MyService class.
When I tried with implementation class package (foo.bar.impl), it complains saying this
I get HTTP ERROR 404; doesn't do anything else; no exceptions on console
When I tried both -- it complains the same as above:
javax.servlet.ServletException: A MultiException has 1 exceptions. They are:|1. java.lang.NoSuchMethodException: Could not find a suitable constructor in foo.bar.MyService class.
What I am doing wrong?
Here's a solution I came across after a few trials (I'm working with jetty 9 and jersey 2.13): instead of annotate the interface (with #Path("/abc")), try to annotate the implementation class instead.
I think this makes good sense since interface are 'abstract' and not supposed to be bound to physical paths. This way, the interface can be reused in different paths.
If you want to use interfaces with JAX-RS annotation you can no longer scan a package with the web.xml
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>XXX</param-value>
You need to manually bind your interface with your resource implementation
bind(YourResource.class).to(YourResourceImpl.class);
Reason for this :
We decided for performance reasons that during scanning the interfaces will be ignored. Also we fixed that Jersey will not try to instantiate interfaces.
https://java.net/jira/browse/JERSEY-1004
I was struggling with the "Could not find a suitable constructor" issue as well. I wanted to put all of my annotations (including #Path) on my interfaces. I was able to make it work by managing the lifecycle of the resources myself rather than have Jersey instantiate them.
For example, if you had YourImplementation which implements YourRestInterface, you'd do something like this to register an instance of the implementation with Jersey:
public class RestConfig extends ResourceConfig {
#Inject
public RestConfig(ServiceLocator locator) {
super();
DynamicConfiguration c = Injections.getConfiguration(locator);
Object implInstance = new YourImplementation();
ServiceBindingBuilder<Object> bb = Injections.newFactoryBinder(new BeanFactory(locator, implInstance));
// tell Jersey to use the factory below to get an instance of YourRestInterface.class
bb.to(YourRestInterface.class);
Injections.addBinding(bb, c);
c.commit();
}
private static class BeanFactory implements Factory<Object> {
private ServiceLocator locator;
private Object bean;
BeanFactory(ServiceLocator locator, Object bean)
{
this.locator = locator;
this.bean = bean;
}
#Override
public Object provide() {
// have Jersey inject things annotated with #Context
locator.inject(bean);
return bean;
}
#Override
public void dispose(Object instance) {
}
}
}
In the class ResourceConfig, there is a constructor like this
ResourceConfig(Class<?>... classes)
The constructor create a new resource configuration initialized with a given set of resource/provider classes.
So you can extend ResourceConfig to register the implementation class.
public class RestConfig extends ResourceConfig {
public RestConfig() {
// register the implementation class
super(MyServiceImpl.class);
}
}
Then, configure web.xml.
<servlet>
<servlet-name>Scivantage REST Service</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<!-- the path of RestConfig -->
<param-value>foo.bar.RestConfig</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
But the simplest way is that register the implementation class in web.xml.
<servlet>
<servlet-name>Scivantage REST Service</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<!-- the path of implementation class -->
<param-value>foo.bar.impl.MyServiceImpl</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Yes you can use the interface to annotate. In our application we have implemented by this way. following quote is taken from Jersy specifications.
JAX-RS annotations MAY be used on the methods and method parameters of
a super-class or an implemented interface. Such annotations are
inherited by a corresponding sub-class or implementation class method
provided that method and its parameters do not have any JAX-RS
annotations of its own. Annotations on a super-class take precedence
over those on an implemented interface. If a subclass or
implementation method has any JAX-RS annotations then all of the
annotations on the super class or interface method are ignored
I think in your case the error because of you may have missed mapping please check.
<servlet-mapping>
<servlet-name>api</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>

how replace XmlGregorianCalendar by Date?

I have to expose an ejb service layer via jax-ws .
I have generated the web service using jax-ws and wsimport but I'm stopped by a strange things ; Date are being mapped to XmlGregorianCalendar .
Is it possible to use classic java Date instead ?
Can you show me the right way to proceed ?
Thanks .
Edit:
this the binding file i used :
thanks , I modified slightly your xml and attached it with netbeans to the client's webservice and it worked . This the binding I used :
<jaxws:bindings node="wsdl:definitions/wsdl:types/xsd:schema"
xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" wsdlLocation="../wsdl/localhost_8080/web_test/Testor.wsdl" >
<jaxb:globalBindings>
<jaxb:javaType name="java.util.Date"
xmlType="xsd:dateTime"
parseMethod="lol.XsdDateTimeConverter.unmarshal"
printMethod="lol.XsdDateTimeConverter.marshalDateTime"
/><jaxb:javaType
name="java.util.Date"
xmlType="xsd:date"
parseMethod="lol.XsdDateTimeConverter.unmarshal"
printMethod="lol.XsdDateTimeConverter.marshalDate"
/>
</jaxb:globalBindings>
</jaxws:bindings>
Not tested, but should work. First create such class:
import javax.xml.bind.DatatypeConverter;
public class XsdDateTimeConverter {
public static Date unmarshal(String dateTime) {
return DatatypeConverter.parseDate(dateTime).getTime();
}
public static String marshalDate(Date date) {
final GregorianCalendar calendar = new GregorianCalendar();
calendar.setTime(date);
return DatatypeConverter.printDate(calendar);
}
public static String marshalDateTime(Date dateTime) {
final GregorianCalendar calendar = new GregorianCalendar();
calendar.setTime(dateTime);
return DatatypeConverter.printDateTime(calendar);
}
}
Then add this to custom xjb file:
<javaType
name="java.util.Date"
xmlType="xs:dateTime"
parseMethod="XsdDateTimeConverter.unmarshal"
printMethod="XsdDateTimeConverter.marshalDateTime"
/>
<javaType
name="java.util.Date"
xmlType="xs:date"
parseMethod="XsdDateTimeConverter.unmarshal"
printMethod="XsdDateTimeConverter.marshalDate"
/>
</globalBindings>
Not tested, but should work. Based on my answer here: JAX-WS and Joda-Time?
Thanks Tomasz. The above solution works.
But wsimport also adds its set of Adapters like Adapter1.java and Adapter2.java with its package org.w3._2001.xmlschema, which really doesnot match my own package structure.
I found a way to change this package name using another jaxb binding. Actually, I searched for this a lot and could not find this easily, so I am adding it here for anyone looking for the same.
Add the following binding in the wsimport using '-b binding.xml'. Note that wsimport can work with multiple binding files.
binding.xml content below:
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
jaxb:version="2.0">
<annotation><appinfo>
<jaxb:schemaBindings>
<jaxb:package name="com.abc.xyz.utils"/>
</jaxb:schemaBindings>
</appinfo></annotation>
</schema>