I am running a JSE application with Restlet 2.1. I am attempting to use the application context, and am finding that it is always null in my application. Because it is null, I cannot seem to access anything -- including any attributes that I pass when I invoke the resource.
The code for the restlet application class is below:
package net.factor3.mailapp;
import net.factor3.mailapp.impl.PageServerImpl;
import org.restlet.Application;
import org.restlet.Context;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.Restlet;
import org.restlet.Server;
import org.restlet.data.MediaType;
import org.restlet.data.Protocol;
import org.restlet.routing.Router;
import org.restlet.routing.Template;
public class MyServer extends Application
{
public MyServer()
{
setName("Test Application");
setDescription("Testing use of Restlets");
}
#Override
public Restlet createInboundRoot()
{
Context ctx = getContext();
Router route = new Router(ctx);
route.setDefaultMatchingMode(Template.MODE_EQUALS);
route.attach("http://localhost:8100/",PageServerImpl.class);
route.attach("http://localhost:8100/{page}",PageServerImpl.class);
return(route);
}
public static void main(String[] args) throws Exception
{
Server asrv = new Server(Protocol.HTTP,8100);
asrv.setNext(new MyServer());
asrv.start();
}
}
Note that the PageServerImpl is a ServerResource. In createInboundRoot(), I use getContext() to get the application's context and put it into ctx. ctx is always null, and I believe for that reason parameters and attributes are lost in the ServerResource.
Is this a bug in the JRE version of Restlet 2.1? If it is, where do I go to report it? There is no clear link to bug reports on the Restlet website.
If it is not a bug, then how do I get a decent context in an application of this kind???
Someone please advise.
Using Component Class you can create statisfy your need:
public class MyServer extends Application
{
public MyServer()
{
setName("Test Application");
setDescription("Testing use of Restlets");
}
public static void main(String[] args) throws Exception
{
// Create a new Restlet component and add a HTTP server connector to it
Component component = new Component();
component.getServers().add(Protocol.HTTP, 8182);
// Then attach it to the local host
component.getDefaultHost().attach("/trace", GenericResource.class);
// Now, let's start the component!
// Note that the HTTP server connector is also automatically started.
component.start();
}
}
Related
We have a React Native app which shows our mobile website and adds some extra features.
Since Android 12 App links (like domain.com) always open our app: https://developer.android.com/training/app-links
This behaviour is not always desirable, for example in this scenario:
Customer is logged in and starts an order via their browser
Customer needs to pay via an app from their bank
After payment, the customer is redirected back to our website (domain.com/returnUrl)
Now the app is opened, instead of the browser, so the customer isn't logged-in and isn't allowed to view the page.
In this case, after payment started from the browser, we would like to redirect the customer back to the browser instead of the app.
Is there a way to open a link in the browser (ie. via domain.com/returnUrl?force-browser) instead of the app?
Related: Android App link - Open a url from app in browser without triggering App Link
Based on this answer, I've created a RN Native Module and instead of using await Linking.openURL(url) you can just use the Native Module's exposed method to open Android App links.
I've followed the official RN tutorial to make an Android Native Module.
So in summary, first you will have to create a Java class file inside android/app/src/main/java/com/your-app-name/folder. I've named the module DefaultBrowserModule so the path is src/main/java/com/your-app-name/DefaultBrowserModule.java. Here's how it looks like:
package com.your-app-name;
import android.content.Intent;
import android.net.Uri;
import androidx.annotation.NonNull;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
public class DefaultBrowserModule extends ReactContextBaseJavaModule {
private ReactApplicationContext _context;
DefaultBrowserModule(ReactApplicationContext context) {
super(context);
this._context = context;
}
#NonNull
#Override
public String getName() {
return "DefaultBrowserModule";
}
// This is the method that we're exposing
#ReactMethod
public void openUrl(String url) {
Intent defaultBrowser = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, Intent.CATEGORY_APP_BROWSER);
defaultBrowser.setData(Uri.parse(url));
// Through ReactApplicationContext's current activty, start a new activity
this._context.getCurrentActivity().startActivity(defaultBrowser);
}
}
After that we'll have to register the module with React Native. That can be done by adding a new Java class file to the android/app/src/main/java/com/your-app-name/ folder. I've named mine DefaultBrowserPackage: src/main/java/com/your-app-name/DefaultBrowserPackage.java:
package com.your-app-name;
import androidx.annotation.NonNull;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class DefaultBrowserPackage implements ReactPackage {
#NonNull
#Override
public List<NativeModule> createNativeModules(#NonNull ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new DefaultBrowserModule(reactContext));
return modules;
}
#NonNull
#Override
public List<ViewManager> createViewManagers(#NonNull ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
The last step is to register the DefaultBrowserPackage inside of MainApplication.java (android/app/src/main/java/com/your-app-name/MainApplication.java). Locate ReactNativeHost’s getPackages() method and add your package to the packages list
#Override
protected List<ReactPackage> getPackages() {
#SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
// below DefaultBrowserPackage is added to the list of packages returned
packages.add(new DefaultBrowserPackage());
return packages;
}
Now we are ready to use it inside of JS. So wherever you want to use it, you can do it like this:
import { Linking, NativeModules, Platform } from 'react-native';
// DefaultBrowserModule should be equal to the return value of the getName() method
// inside of the src/main/java/com/your-app-name/DefaultBrowserModule.java class
const { DefaultBrowserModule } = NativeModules;
export const openUrl = async (url) => {
if (Platform.OS === 'android') {
DefaultBrowserModule.openUrl(url);
} else {
await Linking.openURL(url);
}
};
// And then use it like this
await openUrl('https://my-app-link-domain.com');
Deep and universal linking happens on the operating level and it's hard to control the behavior of other app linking I think it should security breach as some apps try to override the deep link behaviors of another app.
Try to create your simple page with your custom URL https://my-domain.com which redirect to tour target URL without opening associated app.
The best possible solution for that can be using android:pathPattern in android manifest. Basically you have to provide path pattern (a sort regex) to match the valid links.
Documentation for that can be found here.
https://developer.android.com/guide/topics/manifest/data-element
For some reason I can't work out yet, my agent doesn't intercept java LinkageError instances.
Agent code:
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.SuperMethodCall;
import net.bytebuddy.matcher.ElementMatchers;
import java.lang.instrument.Instrumentation;
public class MyAgent {
public static void premain(String arguments, Instrumentation instrumentation) {
new AgentBuilder.Default()
.type(ElementMatchers.isSubTypeOf(LinkageError.class))
.transform((builder, type, classLoader, module) ->
builder.constructor(ElementMatchers.isDefaultConstructor())
.intercept(SuperMethodCall.INSTANCE.andThen(MethodDelegation.to(MyInterceptor.class)))
).installOn(instrumentation);
}
}
Interceptor code:
public class MyInterceptor {
#RuntimeType
public static void intercept(#Origin Constructor<?> constructor) throws Exception {
System.out.println("Intercepted: " + constructor.getName());
}
}
Test code:
public static void main(String[] args) {
new NoClassDefFoundError("should be intercepted!!!").toString();
new Foo("oh").toString();
}
What is puzzling is that replacing ElementMatchers.isSubTypeOf(LinkageError.class) with ElementMatchers.nameContains("Foo") gives the expected result and Foo constructor is intercepted.
The NoClassDefFoundError is loaded by the bootstrap loader. It willnot be able to see your interceptor class which is why it is never triggered.
Try using the Advice class (as a visitor) to add bytecode to matched classes which should resolve this problem.
I am creating a RESTful Web Service that wraps an antiquated vendor API. Some external configuration will be required and will be stored on the server either in a file or rdbms. I'm using Jersey 1.11.1 in Glassfish 3.1.2. This configuration data is all in String key/value format.
My first question is this - where can I store global/instance variables in Jersey so that they will be persisted between requests and available to all resources? If this was a pure Servlet application I would use the ServletContext to accomplish this.
The second part to the question is how can I load my configuration once the Jersey server has loaded? Again, my Servlet analogy would be to find the equivalent to the init() method.
#Singleton #Startup EJB matches your requirements.
#Singleton
#Startup // initialize at deployment time instead of first invocation
public class VendorConfiguration {
#PostConstruct
void loadConfiguration() {
// do the startup initialization here
}
#Lock(LockType.READ) // To allow multiple threads to invoke this method
// simultaneusly
public String getValue(String key) {
}
}
#Path('/resource')
#Stateless
public class TheResource {
#EJB
VendorConfiguration configuration;
// ...
}
EDIT: Added annotation as per Graham's comment
You can use a listener for init the variables and set to the context as attribute before the web application start, something like the following:
package org.paulvargas.shared;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class LoadConfigurationListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
// read file or rdbms
...
ServletContext context = sce.getServletContext();
// set attributes
...
}
public void contextDestroyed(ServletContextEvent sce) {
ServletContext context = sce.getServletContext();
// remove attributes
...
}
}
This listener is configured in the web.xml.
<listener>
<listener-class>org.paulvargas.shared.LoadConfigurationListener</listener-class>
</listener>
You can use the #Context annotation for inject the ServletContext and retrieving the attribute.
package org.paulvargas.example.helloworld;
import java.util.*;
import javax.servlet.ServletContext;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
#Path("/world")
public class HelloWorld {
#Context
private ServletContext context;
#GET
#Produces("text/plain; charset=UTF-8")
public String getGreeting() {
// get attributes
String someVar = (String) context.getAttribute("someName")
return someVar + " says hello!";
}
}
I have several independent Java EE modules (WAR web applications, and JAR EJB modules) which I deploy on JBoss 7.1.1 AS.
I want to:
Centralize configuration of these modules in one *.properties file.
Make this file available in classpath.
Keep the installation/configuration of this file as simple as possible. Ideally would be just to put it in some JBoss folder like: ${JBOSS_HOME}/standalone/configuration.
Make changes to this file available without restarting the application server.
Is this possible?
I already found this link: How to put an external file in the classpath, which explains that preferable way to do this is to make static JBoss module. But, I have to make dependency to this static module in every application module that I deploy, which is a kind of coupling I'm trying to avoid.
Maybe a simple solution is to read the file from a singleton or static class.
private static final String CONFIG_DIR_PROPERTY = "jboss.server.config.dir";
private static final String PROPERTIES_FILE = "application-xxx.properties";
private static final Properties PROPERTIES = new Properties();
static {
String path = System.getProperty(CONFIG_DIR_PROPERTY) + File.separator + PROPERTIES_FILE;
try {
PROPERTIES.load(new FileInputStream(path));
} catch (MalformedURLException e) {
//TODO
} catch (IOException e) {
//TODO
}
}
Here is a full example using just CDI, taken from this site.
This configuration will also work for JBoss AS7.
Create and populate a properties file inside the WildFly configuration folder
$ echo 'docs.dir=/var/documents' >> .standalone/configuration/application.properties
Add a system property to the WildFly configuration file.
$ ./bin/jboss-cli.sh --connect
[standalone#localhost:9990 /] /system-property=application.properties:add(value=${jboss.server.config.dir}/application.properties)
This will add the following to your server configuration file (standalone.xml or domain.xml):
<system-properties>
<property name="application.properties" value="${jboss.server.config.dir}/application.properties"/>
</system-properties>
Create the singleton session bean that loads and stores the application wide properties
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import javax.annotation.PostConstruct;
import javax.ejb.Singleton;
#Singleton
public class PropertyFileResolver {
private Logger logger = Logger.getLogger(PropertyFileResolver.class);
private String properties = new HashMap<>();
#PostConstruct
private void init() throws IOException {
//matches the property name as defined in the system-properties element in WildFly
String propertyFile = System.getProperty("application.properties");
File file = new File(propertyFile);
Properties properties = new Properties();
try {
properties.load(new FileInputStream(file));
} catch (IOException e) {
logger.error("Unable to load properties file", e);
}
HashMap hashMap = new HashMap<>(properties);
this.properties.putAll(hashMap);
}
public String getProperty(String key) {
return properties.get(key);
}
}
Create the CDI Qualifier. We will use this annotation on the Java variables we wish to inject into.
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({ ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR })
public #interface ApplicationProperty {
// no default meaning a value is mandatory
#Nonbinding
String name();
}
Create the producer method; this generates the object to be injected
import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.inject.Inject;
public class ApplicationPropertyProducer {
#Inject
private PropertyFileResolver fileResolver;
#Produces
#ApplicationProperty(name = "")
public String getPropertyAsString(InjectionPoint injectionPoint) {
String propertyName = injectionPoint.getAnnotated().getAnnotation(ApplicationProperty.class).name();
String value = fileResolver.getProperty(propertyName);
if (value == null || propertyName.trim().length() == 0) {
throw new IllegalArgumentException("No property found with name " + value);
}
return value;
}
#Produces
#ApplicationProperty(name="")
public Integer getPropertyAsInteger(InjectionPoint injectionPoint) {
String value = getPropertyAsString(injectionPoint);
return value == null ? null : Integer.valueOf(value);
}
}
Lastly inject the property into one of your CDI beans
import javax.ejb.Stateless;
import javax.inject.Inject;
#Stateless
public class MySimpleEJB {
#Inject
#ApplicationProperty(name = "docs.dir")
private String myProperty;
public String getProperty() {
return myProperty;
}
}
I am new to struts and spring security.
Can anyone help me to figure out how to redirect to different urls different users with different roles ? In other words, how to provide determine target url based on user role in struts2 using action controller?
I found the following question determine target url based on roles in spring security 3.1 , but I cannot figure out how to configure the action.
I tried the following setup, but it does not work:
security.xml
<form-login login-page="/login" authentication-failure-url="/login?error=true" login-processing-url="/j_security_check" default-target-url="/default"/>
struts.xml
<action name="default" class="com.moblab.webapp.action.RoleRedirectAction" method="defaultAfterLogin"/>
RoleRedirectAction.java
package com.moblab.webapp.action;
import javax.servlet.http.HttpServletRequest;
public class RoleRedirectAction extends BaseAction{
public String defaultAfterLogin(HttpServletRequest request) {
if (request.isUserInRole("ROLE_ADMIN")) {
return "redirect:/<url>";
}
return "redirect:/<url>";
}
}
Thanks a lot.
EDIT 1
I also tried the following annotation
#Action(value="/default",results={#Result(name="success",location="/querySessions")})
EDIT 2
My final solution looks like the following. I am not sure if it is the best approach, but it works:
public class StartPageRouter extends SimpleUrlAuthenticationSuccessHandler {
#Autowired
private UserService userService;
protected final Logger logger = Logger.getLogger(this.getClass());
private RequestCache requestCache = new HttpSessionRequestCache();
#Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
//default path for ROLE_USER
String redirectPath = <url>;
if (authorities != null && !authorities.isEmpty()) {
Set<String> roles = getUserRoles(authorities);
if (roles.contains("ROLE_ADMIN"))
redirectPath = <url>;
else if (roles.contains("ROLE_INSTRUCTOR"))
redirectPath = <url>;
}
getRedirectStrategy().sendRedirect(request, response, redirectPath);
}
public void setRequestCache(RequestCache requestCache) {
this.requestCache = requestCache;
}
private Set<String> getUserRoles(Collection<? extends GrantedAuthority> authorities) {
Set<String> userRoles = new HashSet<String>();
for (GrantedAuthority authority : authorities) {
userRoles.add(authority.getAuthority());
}
return userRoles;
}
}
EDIT 3
There are even better solutions here:
http://oajamfibia.wordpress.com/2011/07/07/role-based-login-redirect/#comment-12
Assuming that you mean that you want to redirect users to different start pages depending on their assigned roles then you can try this. Note that I do all this outside of Struts.
First create your own class that extends Springs SimpleUrlAuthenticationSuccessHandler and override the onAuthenticationSuccess() method. The actual redirect is performed within the onAuthenticationSuccess() method by the line getRedirectStrategy().sendRedirect(request,response,);
So all you need is a means of substituting your own url's.
So, for example I have
package com.blackbox.x.web.security;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import com.blackbox.x.entities.UserDTO;
import com.blackbox.x.services.UserService;
public class StartPageRouter extends SimpleUrlAuthenticationSuccessHandler {
#Autowired
UserService userService;
#Autowired
LoginRouter router;
protected final Logger logger = Logger.getLogger(this.getClass());
private RequestCache requestCache = new HttpSessionRequestCache();
#Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication) throws IOException,
ServletException {
requestCache.removeRequest(request, response);
User user = (User) authentication.getPrincipal();
UserDTO userDTO = userService.find(user.getUsername());
getRedirectStrategy().sendRedirect(request, response, router.route(userDTO));
}
public void setRequestCache(RequestCache requestCache) {
this.requestCache = requestCache;
}
}
where LoginRouter is my own class that takes the logged in user and, from the assigned roles determines which URL the user should be directed to.
You then configure Spring Security to use your version using the
authentication-success-handler-ref="customTargetUrlResolver"/>
and
<beans:bean id="customTargetUrlResolver" class="com.blackbox.x.web.security.StartPageRouter"/>
in your security context xml file.