Need to "inject" #ApplicationScoped bean into Liferay hook - liferay-6

Both the managed bean and the hook are in the same war. I'm using 6.1 CE on Tomcat 7.
I'm trying to remove some data from the ApplicationScoped bean during the run method of a Hook tied to logout.events.pre.
The run method is called with an HttpServletRequest, and I've read that the bean should be accessible as an attribute of that HttpServletRequest or alternatively of the ServletContext I can get from the HttpServletRequest, but both methods return null.
I've enumerated all keys, and it's just not there.
Does anyone know how to acheive what I need?
Thanks.
#Override
public void run(HttpServletRequest req, HttpServletResponse res) {
System.out.println("In custom pre LogoutAction....");
ServletContext servletContext = req.getServletContext();
// DataBean dataBean = (DataBean) servletContext.getAttribute("com.xvest.hooks.DataBean");
// DataBean dataBean = (DataBean) req.getAttribute("dataBean");
// Find loggedInUser and impersonatedUser.
ThemeDisplay themeDisplay = (ThemeDisplay) req.getAttribute("THEME_DISPLAY");
User loggedInUser = themeDisplay.getRealUser();
User impersonatedUser = themeDisplay.getUser();
// Fetch CompleterHousehold for impersonatedUser.
CompleterHousehold completerHousehold = dataBean.fetch(impersonatedUser, loggedInUser);
// Delete loggedInUser from CompleteHousehold.viewers
boolean result = completerHousehold.deleteViewer(loggedInUser);
// If the delete returns true, there are no more viewers for this household, so delete the CompleterHousehold from DataBean.
if (result)
dataBean.delete(impersonatedUser);
}

Related

Autofac fails to resolve enumerable of typed HttpClients

I have a number of services which require usage of typed HttpClient from HttpClientFactory.
Though I can resolve one service I can't resolve IEnumerable of this services.
interface IMyHttpClient
{
}
class MyHttpClient: IMyHttpClient
{
public MyHttpClient(HttpClient client)
{
}
}
class Program
{
static void Main(string[] args)
{
var services = new ServiceCollection();
services.AddHttpClient()
.AddHttpClient<IMyHttpClient, MyHttpClient>();
var builder = new ContainerBuilder();
// Exception goes away when remove this line
builder.RegisterType<MyHttpClient>().As<IMyHttpClient>();
builder.Populate(services);
var provider = builder.Build();
// ============== This works
// provider.Resolve<IMyHttpClient>();
// ============== This throws exception
provider.Resolve<IEnumerable<IMyHttpClient>>();
}
}
Constructor will be called once and than exception is thrown:
```
DependencyResolutionException: None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'ConsoleApp2.MyHttpClient' can be invoked with the available services and parameters:
Cannot resolve parameter 'System.Net.Http.HttpClient client' of constructor 'Void .ctor(System.Net.Http.HttpClient)'.
```
The issue is that AddHttpClient adds it's own registration of IMyHttpClient. But I do want to register using Autofac only! Is there a way to use typed clients but still stay with Autofac?
The exception explains that Autofac can't resolve parameter 'System.Net.Http.HttpClient client'. I suppose this is because such type wasn't registered in your container for second resgistration of IMyHttpClient. To save an advantages of HttpClientFactory you can register excplicit constructor parameter for example like this:
static void Main(string[] args)
{
var services = new ServiceCollection();
services.AddHttpClient();
var builder = new ContainerBuilder();
// exclicit resolving client for constructor
builder.RegisterType<MyHttpClient>().As<IMyHttpClient>().WithParameter(
(p, ctx) => p.ParameterType == typeof(HttpClient),
(p, ctx) => ctx.Resolve<IHttpClientFactory>().CreateClient());
builder.Populate(services);
var provider = builder.Build();
// ============== This works
provider.Resolve<IMyHttpClient>();
// ============== This works too
provider.Resolve<IEnumerable<IMyHttpClient>>();
}
In this example Resolve<IEnumerable<IMyHttpClient>> return enumeration with single IMyHttpClient, that is initialized with HttpClient from core HttpClientFactory.
UPD: the post was updated by #norekhov comment

How to mock a RemoteServiceServlet with HttpRequestSession

Here is a code snippet of my RemoteServiceServlet. The function getSubject(), obtains the session from the HttpServletRequest, which refers to the getThreadLocalRequest. I am making a junit test to test this server, however the getThreadLocalRequest is not populated and returns null.
public class Server extends XsrfProtectedServiceServlet implements RemoteInterface {
private static final long serialVersionUID = 2230123191888380541L;
public Server() throws IOException
{
credentials = new PropertiesCredentials(Server.class.getResourceAsStream("AwsCredentials.properties.email"));
database = new Database();
}
public Subject getSubject()
{
HttpServletRequest request = this.getThreadLocalRequest();
HttpSession session = request.getSession(false);
Subject subject = (Subject)session.getAttribute("subject");
return subject;
}
}
This is my junit test
#Test
public void testserver()
{
Server s = new Server();
s.getSubject();
}
s.getSubject fails because the session is not populated. How can I mock Server so that I can populate a session.
You'll need to use a mocking framework to create behaviour around the object under test. I use PowerMock with EasyMock (http://code.google.com/p/powermock/).
What I suggest you do first, though, is refactor the code out of the constructor. As written, this code is very complicated to test, because the getResourceAsStream method is a static method of the underlying Class type. And since it's not used in the method under test (nor is the database reference), I question the need to use the constructor to get the resource bundle.
To test your getSubject() method, essentially what you need to do is create an instance of your class that is a partial mock, where the getThreadLocalRequest is the only method to be mocked:
#RunWith( PowerMockRunner.class )
#PrepareForTest( Server.class )
public class ServerTest {
#Test
public void testGetSubjectReturnsSubjectFromHttpSession() {
// assuming the constructor is cleaned up, create a Server instance...
Server server = PowerMock.createPartialMockAndInvokeDefaultConstructor( Server.class, "getThreadLocalRequest" );
// create a mock object that represents the Http request
HttpServletRequest mockRequest = PowerMock.createMock(HttpServletRequest.class);
EasyMock.expect( server.getThreadLocalRequest() ).andReturns( mockRequest);
// create a mock for the Http Session
HttpSession mockSession = PowerMock.createMock( HttpSession.class );
EasyMock.expect( mockRequest.getSession( EasyMock.anyBoolean() ) ).andReturns( mockSession );
EasyMock.expect( mockSession.getAttribute( EasyMock.isA( String.class ) ).andReturns( mockSubject );
// put the mocks into playback mode
PowerMock.replayAll();
// exercise the method
Subject subject = server.getSubject();
// verify that the mocks were called as you expect them to be...
PowerMock.verifyAll();
// and here you put other assertions that relate to the data returned...
Assert.assertNotNull( subject );
}
}

FrontController with RequestFactory in GWT

I am using RequestFactory with GWT. It all working fine. I have a RequestContext interface that point to my DAO methodes.
Now I want to implement some kind of security check before calling the DAO. The first thing that comes to my mind is to use a FrontController and centralize the security in it, but I don't know to implement it with the RequestFactory. Any thought ?
If you want to test whether the user is authenticated, you can use a servlet filter on the server-side and a custom RequestTransport on the client-side. See the guice-rf-activity archetype at https://github.com/tbroyer/gwt-maven-archetypes for an example.
You can also check on the method-level by using a custom ServiceLayerDecorator and implementing the invoke method, calling report() when the user isn't authorized/authenticated (and handling the onFailure on the client-side). I implemented such a thing, that authorized the user based on #RolesAllowed annotations on the service method or class: https://gist.github.com/tbroyer/6091533
Here's how I implemented the security checking:
On the server side I check to see that every RequestFactory request is associated with a user who has previously logged in. To do this, the web.xml file (in the war/WEB-INF directory) must have a mapping for the servlet class. Here's the entry from the web.xml file:
<servlet>
<servlet-name>requestFactoryServlet</servlet-name>
<servlet-class>org.greatlogic.rfexample2.server.RFERequestFactoryServlet</servlet-class>
<init-param>
<param-name>symbolMapsDirectory</param-name>
<param-value>WEB-INF/classes/symbolMaps/</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>requestFactoryServlet</servlet-name>
<url-pattern>/gwtRequest</url-pattern>
</servlet-mapping>
The RFERequestFactoryServlet class contains the following code:
public class RFERequestFactoryServlet extends RequestFactoryServlet {
#Override
protected void doPost(final HttpServletRequest request, final HttpServletResponse response)
throws IOException, ServletException {
if (!userIsLoggedIn(request)) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
else {
super.doPost(request, response);
}
}
private boolean userIsLoggedIn(final HttpServletRequest request) {
boolean result = false;
HttpSession session = request.getSession();
if (session != null) {
User user = (User)session.getAttribute("User");
result = user != null;
}
return result;
}
}
On the client side I needed to intercept every RequestFactory response to check for the SC_UNAUTHORIZED error. You have to tell the RequestFactory object to use a specific RequestTransport in the RequestFactory#initialize invocation, like this:
MyRequestFactory requestFactory = GWT.create(MyRequestFactory.class);
requestFactory.initialize(eventBus, new RFERequestTransport());
My RFERequestTransport class extends the DefaultRequestTransport class:
public class RFERequestTransport extends DefaultRequestTransport {
private final class RFERequestCallback implements RequestCallback {
private RequestCallback _requestCallback;
private RFERequestCallback(final RequestCallback requestCallback) {
_requestCallback = requestCallback;
}
#Override
public void onError(final Request request, final Throwable exception) {
_requestCallback.onError(request, exception);
}
#Override
public void onResponseReceived(final Request request, final Response response) {
if (response.getStatusCode() == Response.SC_UNAUTHORIZED) {
// the login processing goes here
}
else {
_requestCallback.onResponseReceived(request, response);
}
}
} // end of the RFERequestCallback class
#Override
protected RequestCallback createRequestCallback(final TransportReceiver receiver) {
return new RFERequestCallback(super.createRequestCallback(receiver));
}
}
When RequestFactory creates a request callback it calls my method, which creates my own version of a RequestCallback. If the user is logged in (as determined by the servlet) then it just performs the normal RequestFactory processing; otherwise, I go through the login process with the user. Part of the login process involves communication with the server to verify the login ... if the login is successful then I create an object on the server and store a reference to it in the "User" attribute - this is then checked in the userIsLoggedIn method in the servlet class.
Setup a filter in your web.xml so as every RF request is filtered to validate the session.
<filter>
<filter-name>AuthFilter</filter-name>
<filter-class>my.namespace.AuthFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>AuthFilter</filter-name>
<url-pattern>/gwtRequest</url-pattern>
</filter-mapping>
Here you have an example class, checking if a certain parameter is in session which could be set in the login process to your app, this is just an example, you could use your own mechanism.
public class AuthFilter implements Filter {
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;
if (req.getSession().getAttribute("VALID_SESSION") == null) {
resp.sendError(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
if (null != filterChain) {
filterChain.doFilter(req, resp);
}
}
}

GWT servlet filter ,How to identify special service request?

I created a app with GWT+requestfacotry(MVP)+GAE. There are some service or method exposed to GWT client ,such as
1.create
2.remove
3.query
I want to add authorization function to "create" and "remove" ,but not to "query".
I did it with servlet filter :
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
UserService userService = UserServiceFactory.getUserService();
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
if (!userService.isUserLoggedIn()) {
response.setHeader("login", userService.createLoginURL(request.getHeader("pageurl")));
// response.setHeader("login", userService.createLoginURL(request.getRequestURI()));
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
filterChain.doFilter(request, response);
}
My question is how to identify what request (I mean the request will route to which class and service )coming in ? There are some head fields contain the module name ,but I don't it is the security way to do.
Is it possible to get RequestFacotry relevant class from http request ?
Thanks
It's hard to do this within the servlet-filter. Instead you can provide a custom decorator within the RF ServiceLayerDecorator chain. Implementation can looks like this:
import com.google.web.bindery.requestfactory.server.ServiceLayerDecorator;
public class SecurityDecorator extends ServiceLayerDecorator {
#Override
public Object invoke( Method domainMethod, Object... args ) {
if ( !isAllowed( domainMethod) ) {
handleSecurityViolation();
}
return super.invoke( domainMethod, args );
}
}
To register the additional decorator, provide a custom RF servlet:
import com.google.web.bindery.requestfactory.server.RequestFactoryServlet;
public class SecurityAwareRequestFactoryServlet extends RequestFactoryServlet {
public SecurityAwareRequestFactoryServlet() {
super( new DefaultExceptionHandler(), new SecurityDecorator() );
}
}
and register it in your web.xml:
<servlet>
<servlet-name>gwtRequest</servlet-name>
<servlet-class>com.company.SecurityAwareRequestFactoryServlet</servlet-class>
</servlet>

jBoss deployment of message-driven bean spec violation

I have an java EE application which has one message-driven bean and it runs fine on JBoss 4, however when I configure the project for JBoss 6 and deploy on it, I get this error;
WARN [org.jboss.ejb.deployers.EjbDeployer.verifier] EJB spec violation:
...
The message driven bean must declare one onMessage() method.
...
org.jboss.deployers.spi.DeploymentException: Verification of Enterprise Beans failed, see above for error messages.
But my bean HAS the onMessage method! It would not have worked on jboss 4 either then.
Why do I get this error!?
Edit:
The class in question looks like this
package ...
imports ...
public class MyMDB implements MessageDrivenBean, MessageListener {
AnotherSessionBean a;
OneMoreSessionBean b;
public MyMDB() {}
public void onMessage(Message message) {
if (message instanceof TextMessage) {
try {
//Lookup sessionBeans by jndi, create them
lookupABean();
// check message-type, then invokie
a.handle(message);
// else
b.handle(message);
} catch (SomeException e) {
//handling it
}
}
}
public void lookupABean() {
try {
// code to lookup session beans and create.
} catch (CreateException e) { // handling it and catching NamingException too }
}
}
Edit 2:
And this is the jboss.xml relevant parts
<message-driven>
<ejb-name>MyMDB</ejb-name>
<destination-jndi-name>topic/A_Topic</destination-jndi-name>
<local-jndi-name>A_Topic</local-jndi-name>
<mdb-user>user</mdb-user>
<mdb-passwd>pass</mdb-passwd>
<mdb-client-id>MyMessageBean</mdb-client-id>
<mdb-subscription-id>subid</mdb-subscription-id>
<resource-ref>
<res-ref-name>jms/TopicFactory</res-ref-name>
<jndi-name>jms/TopicFactory</jndi-name>
</resource-ref>
</message-driven>
Edit 3:
I just removed all my jars from the project, and only re-added relevant ones (from new versions also) to put out NoClassDefFound errors.
Still the problem remains.
Edit:
Any directions, what area should I look at? My project, or jboss-configration, or the deployment settings??
org.jboss.ejb.deployers.EjbDeployer.verifier
looks for
public void onMessage(javax.jms.Message)
via some code like this (this is from JBoss5):
/**
* Check if the given message is the onMessage() method
*/
public boolean isOnMessageMethod(Method m)
{
if ("onMessage".equals(m.getName()))
{
Class[] paramTypes = m.getParameterTypes();
if (paramTypes.length == 1)
{
if (Message.class.equals(paramTypes[0]))
return true;
}
}
return false;
}
It is important that the parameter type is javax.jms.Message and nothing else, for example some subclass or superclass or some implementing class.
Your signature is public void onMessage(Message message) which looks ok on first sight.
A Class is equal only in its ClassLoader. If for some reasons javax.jms.Message is available in different classloaders in the same JVM, strange things can happen, depending on the ClassLoader of the EjbDeployer.verifier. Maybe the EjbDeployer.verifer has a access to javax.jms.Message in another ClassLoader as MyMDB. As result, both javax.jms.Message are not equal to each other, although they are the same byte-code and literally exists. The EjbVerifier will warn about missing onMessage, because javax.jms.Message on ClassLoader A is not equal to javax.jms.Message on ClassLoader B.
This can happen when libraries with javax.jms.Message is copied on wrong places on the JBoss AS. So I guess - from a distance - that there is some jars containing javax.jms.Message in wrong places on the JBoss or the EAR. For example some wrong jbossallclient.jar in the EAR.
Make sure your EAR does not contain its own copies of the javax.ejb classes (or any javax classes at all, for that matter). JBoss 4 and 6 have rather different classloading semantics, and what works on one may not work on the other. For example, if your EAR's lib contained its own copies of Message or MessageListener, then it may no longer work.
I tried it out on "JBossAS [6.0.0.20100911-M5 "Neo"]" and Eclipse Helios
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.ejb.MessageDrivenBean;
import javax.ejb.MessageDrivenContext;
import javax.jms.Message;
import javax.jms.MessageListener;
#MessageDriven(
activationConfig = { #ActivationConfigProperty(
propertyName = "destinationType", propertyValue = "javax.jms.Topic"
) },
mappedName = "topic/A_Topic",
messageListenerInterface = MessageListener.class)
public class MyMDB implements MessageListener, MessageDrivenBean {
private static final long serialVersionUID = -4923389997501209506L;
public MyMDB() {
// TODO Auto-generated constructor stub
}
#Override
public void ejbRemove() {
// TODO Auto-generated method stub
}
#Override
public void setMessageDrivenContext(MessageDrivenContext arg0) {
// TODO Auto-generated method stub
}
#Override
public void onMessage(Message message) {
// TODO Auto-generated method stub
}
}
And this setting works. Do you have the same imports for your bean (perhaps there was an automatic import gone wrong???)