Struts 2 how to display messages saved in a Interceptor which would redirec to another action? - redirect

in my interceptor, if user doesn't have enough right, there would be a warn message:
public String intercept(ActionInvocation invocation) throws Exception {
ActionContext actionContext = invocation.getInvocationContext();
Map<String, Object> sessionMap = actionContext.getSession();
User loginUser = (User) sessionMap.get("user");
Object action = invocation.getAction();
if (loginUser != null && loginUser.getRole().getId() != Constant.AUTHORITY_ADMIN) {
((ValidationAware) action).addFieldError("user.authority",
((DefaultAction) action).getText("user.action.authority.not.enough"));
return DefaultAction.HOME_PAGE;
}
return invocation.invoke();
}
then, it would redirect to "HOME_PAGE" action, if success, display information in the jsp. So how to display the warn message?
i have used two interceptors configed in strust.xml, for admin right requirment:
<interceptor-stack name="authorityStack">
<interceptor-ref name="authority" />
<interceptor-ref name="defaultStack" />
<interceptor-ref name="store">
<param name="operationMode">STORE</param>
</interceptor-ref>
</interceptor-stack>
default is:
<interceptor-stack name="default">
<interceptor-ref name="login" />
<interceptor-ref name="defaultStack" />
<interceptor-ref name="store">
<param name="operationMode">AUTOMATIC</param>
</interceptor-ref>
</interceptor-stack>

Here's how I handle access control in Struts2. It's really easy and quite re-usable:
First, create an interface called SecurityCheckAware.
public interface SecurityCheckAware {
void checkRight();
}
Then, create an interceptor called SecurityCheckInterceptor.
public class SecurityCheckInterceptor extends AbstractInterceptor {
#Override
public String intercept(final ActionInvocation invocation) throws Exception {
if (invocation.getAction() instanceof SecurityCheckAware) {
SecurityCheckAware action = (SecurityCheckAware) invocation.getAction();
action.checkRight();
}
return invocation.invoke();
}
}
Then, define the interceptor in your stack.
Any action that you want to perform security checks in should implement SecurityCheckAware. For example:
#Override
public void checkRight() {
User loginUser = (User) session.get("user");
if (loginUser != null && loginUser.getRole().getId() != Constant.AUTHORITY_ADMIN) {
throw new AccessViolation("You do not have permission to access this page.");
}
}
Next, create a custom exception that extends RuntimeException (or some subclass thereof). I call it AccessViolation.
Lastly, map AccessViolation to an error page in your struts.xml, such as:
<global-results>
<result name="accessDenied">/WEB-INF/jsp/accessDenied.jsp</result>
</global-results>
<global-exception-mappings>
<exception-mapping exception="com.example.AccessViolation" result="accessDenied"/>
</global-exception-mappings>
Note: You can fore-go the SecurityCheckAware and SecurityCheckInterceptor and just use the existing Preparable and PrepareInterceptor, but I like being able to encapsulate my security checks in their own method.
This doesn't rely on redirection or action/field errors (as in your question), but it should deliver everything you're looking for.

I use MessageStoreInterceptor and it's easy.
MessageStoreInterceptor - http://struts.apache.org/release/2.3.x/docs/message-store-interceptor.html
Let me know if you need more help.

Related

Can I order my TestNG listeners?

I have a situation where I need to enable/disable tests(using AnnotationTransformer listener) based on the parameter coming from my suite files(using ISuiteListener listener). However, when I try to read the parameters in my suite file before calling AnnotationTransformer, I am not able to do so.
This does not help:
<listeners preserve-order="true">
<listener class name="automation.test.SentinelSuiteListener" />
<listener class-name="automation.test.AnnotationTransformer" />
</listeners>
Also, when I try to implement both these interfaces together, the method for AnnoataionTransformer i.e. transform goes before the onStart() method:
public class AnnotationTransformer implements IAnnotationTransformer, ISuiteListener {
String currentRunModeInSuite;
#Override
public void onStart(ISuite suite) {
currentRunModeInSuite = suite.getParameter("currentRunMode");
}
#Override
public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) {
System.out.println("***Test case under review : " + testMethod.getName());
for(int i=0; i<annotation.getGroups().length;i++){
System.out.println(annotation.getGroups()[i]);
}
System.out.println(currentRunModeInSuite);
}
#Override
public void onFinish(ISuite suite) {
// TODO Auto-generated method stub
}
}
The behavior you seen is the expected one because TestNG works step by step.
First, it looks for tests and reads their datas. You can be triggered if you want to change them and it's the goal of IAnnotationTransformer.
Then, TestNG runs suite/tests/classes/methods and you can be triggered by that with ISuiteListener or else.
What you need is IMethodInstance which is called during the run: http://testng.org/doc/documentation-main.html#methodinterceptors
Fyi, the <listeners> node doesn't accept preserve-order attribute. See the documentation: http://testng.org/testng-1.0.dtd.php

update dynamically targeting provider in iPOJO

I have a component declared as:
<ipojo>
<component classname="HelloClass" name="helloCom" immediate="true">
<requires field="delayService" id="id1">
</requires>
</component>
<instance component="helloCom" name="hello">
<property name="requires.from">
<property name="id1" value="A"/>
</property>
</instance>
</ipojo>
The jar file of this component :helloComponent.jar
Now, i want to update (value="A") to (value="AA"). Thus, i implement a component using ConfigurationAdmin to update this property
public class ControllerReconfiguration {
private ConfigurationAdmin m_configAdmin;
#SuppressWarnings({ "rawtypes", "unchecked" })
public void reconfigure() throws IOException {
Configuration configuration = m_configAdmin.getConfiguration("hello","file:./helloComponent.jar");
configuration.setBundleLocation("file:./helloComponent.jar");
Properties props = new Properties();
//Dictionary props = new Hashtable();
props.put("id1", "AA");
configuration.update(props);
System.out.println("Update");
}
}
However, this ControllerReconfiguration component can't update the value 'A' (by 'AA') in 'hello' instance.
How to modify this ControllerReconfiguration component, please ?
Thanks you for your help.
Unfortunately, you can't push new 'from' configuration like this.
However, you can use the iPOJO introspection API directly: http://felix.apache.org/documentation/subprojects/apache-felix-ipojo/apache-felix-ipojo-userguide/ipojo-advanced-topics/using-ipojo-introspection-api.html
Retrieve the Architecture service of the instance
Retrieve the InstanceDescription and DependencyDescription
Call the setFilter method
Thanks Clement,
it works fine !!!!! :) I access InstanceManager using Factory.
Ex, in order to access InstanceManager of component "hello.call.CallHello"
#require
private Factory[] factories;
for (Factory factory : factories) {
/*
* "hello.call.CallHello" is a component name
* note: it is not component instance name
*/
if (factory.getName().equals("hello.call.CallHello")) {
/*
* a component can have many instances
* if there is only one instance.
* get(0) return the first instance.
*/
InstanceManager im = (InstanceManager) factory.getInstances().get(0);
}

MvvmCross passing configuration to configurable plugin loader

I am creating a portable MockGeoLocationWatcher that one can substitute in place of the concrete implementations of IMvxGeoLocationWatcher until one has an actual device. This should facilitate development and testing of applications that require geo location.
The PluginLoader class for this plugin currently looks like this:
namespace Pidac.MvvmCross.Plugins.Location
{
public class PluginLoader : IMvxConfigurablePluginLoader
{
private bool _loaded;
public static readonly PluginLoader Instance = new PluginLoader();
public void EnsureLoaded()
{
if (_loaded)
return;
_loaded = true;
var locationWatcher = new MockGeoLocationWatcher();
var data = #"<?xml version='1.0' encoding='utf-8'?>
<WindowsPhoneEmulator xmlns='http://schemas.microsoft.com/WindowsPhoneEmulator/2009/08/SensorData'>
<SensorData>
<Header version='1' />
<GpsData latitude='48.619934106826' longitude='-84.5247359841114' />
<GpsData latitude='48.6852544862377' longitude='-83.9864059059864' />
<GpsData latitude='48.8445703681025' longitude='-83.7337203591114' />
<GpsData latitude='48.8662561090809' longitude='-83.2393355934864' />
<GpsData latitude='49.0825970371386' longitude='-83.0415816872364' />
<GpsData latitude='49.2621642999055' longitude='-82.7229781716114' />
<GpsData latitude='49.2621642999055' longitude='-82.6021285622364' />
<GpsData latitude='49.2047736379815' longitude='-82.3054977028614' />
</SensorData>
</WindowsPhoneEmulator>";
locationWatcher.SensorLocationData = data;
Mvx.RegisterSingleton(typeof(IMvxGeoLocationWatcher), locationWatcher);
}
public void Configure(IMvxPluginConfiguration configuration)
{
}
}
public class MockLocationWatcherConfiguration : IMvxPluginConfiguration
{
public static readonly MockLocationWatcherConfiguration Default = new MockLocationWatcherConfiguration();
// ideally, we should use this property to point to a file or string containing location data
// this should be configurable outside of code base.
public string SensorLocationData { get; set; }
}
}
I will like to pass the sensor data, currently hardcoded into the variable called "data" through an instance of MockLocationWatcherConfiguration but do not know where the MvvmCross framework is expecting to load the configuration for this plugin before IMvxConfigurablePluginLoader.Configure(configuration) is invoked. Ideally, I should specify this through configuration.
I looked at the Json plugin's implementation of PluginLoaded but still could not figure out where the configuration was retrieved before a cast was attempted in IMvxConfigurablePluginLoader.Configure.
Any ideas or pointers will be greatly appreciated.
TIA.
This is covered in the draft wiki page https://github.com/slodge/MvvmCross/wiki/MvvmCross-plugins - see "writing a configurable plugin"

Struts2 Load ALL values in a s:select tag into a HashMap in the action class

I have researched enough on this topic sans any luck :-(
My requirement is to load a HashMap that is declared in the action class from the jsp form that has a s:select tag.
Here is my action class
public class AttributeAction extends ActionSupport {
private HashMap<String, String> lstAttrTypesHashMap;
public void setLstAttrTypesHashMap(HashMap<String, String> lstAttrTypesHashMap) {
this.lstAttrTypesHashMap = lstAttrTypesHashMap;
}
public HashMap<String, String> getLstAttrTypesHashMap() {
return lstAttrTypesHashMap;
}
public String renderPageAction() {
lstAttrTypesHashMap.put("ENTRY1", "VALUE1");
lstAttrTypesHashMap.put("ENTRY2", "VALUE2");
lstAttrTypesHashMap.put("ENTRY3", "VALUE3");
return SUCCESS;
}
public String searchAction() {
logger.info("***************************************");
logger.info("searchAction Started ...");
logger.info("a.getType() = [" + a.getType() + "]");
logger.info("getLstAttrTypesHashMap() = [" + getLstAttrTypesHashMap() + "]");
return SUCCESS;
}
}
here is how I show the drop down in the jsp
<s:select
key="a.type"
label="Select Object Type"
name="a.type"
list="lstAttrTypesHashMap" />
Here is the struts.xml
<action name="attributeSearch" method="searchAction" class="com.frk.gid.action.AttributeAction">
<result name="success">/AttributeResult.jsp</result>
<result name="input">/AttributeInput.jsp</result>
</action>
<action name="attributeRender" method="renderPageAction" class="com.frk.gid.action.AttributeAction">
<result name="success">/AttributeInput.jsp</result>
</action>
When the above jsp loads, I can see that the drop down is populated fine. However when I submit it back to the action, i can only see the selected value (a.type) . The hashmap happens to be null. Is there anything else I need to do to get this HashMap loaded? My understanding was Struts2 would automatically load the HashMap from the dropdown on submit - apparently not ... appreciate any input !!!!
Thanks very much for your responses !
Finally I decided to go with passing Hidden variables and it worked like a charm.
Also, I had complex types like Map>, I had to write my own Type Converter to convert from and to String.

get list of services implementations with OSGi declarative services

I have a very simple example of declarative services. I'm following this tutorial http://www.eclipsezone.com/eclipse/forums/t97690.html?start=0. Every thing is working as expected. However, I cannot figure out how I can make the "SampleImporter" (which is the bundle that is expected to use other bundles' services) aware of the list of "SampleExporter" (bundle providing a service). In other words, I want the "SamlpeImporter" to see the ID of the bundle(s) that it is eventually using. This information is very useful for my application.
here is the XML file for SampleExporter:
<?xml version="1.0"?>
<component name="samplerunnable">
<implementation class="org.example.ds.SampleRunnable"/>
<property name="ID" value="expoter" />
<service>
<provide interface="java.lang.Runnable"/>
</service>
while for the SampleImporter:
<?xml version="1.0"?>
<component name="commandprovider1">
<implementation class="org.example.ds.SampleCommandProvider1"/>
<service>
<provide interface="org.eclipse.osgi.framework.console.CommandProvider"/>
</service>
<reference name="RUNNABLE"
interface="java.lang.Runnable"
bind="setRunnable"
unbind="unsetRunnable"
cardinality="0..1"
policy="dynamic"/>
</component>
In the Importer side, I have the following function:
public class SampleCommandProvider1 implements CommandProvider {
private Runnable runnable;
public synchronized void setRunnable(Runnable r) {
runnable = r;
}
public synchronized void unsetRunnable(Runnable r) {
runnable = null;
}
public synchronized void _run(CommandInterpreter ci) {
if(runnable != null) {
runnable.run();
} else {
ci.println("Error, no Runnable available");
}
}
public String getHelp() {
return "\trun - execute a Runnable service";
}
}
This works fine but then if I want to get the value of the property, using
public synchronized void setRunnable(Runnable r, Map properties)
or
public synchronized void setRunnable(Runnable r, ServiceReference reference)
the method run of the exporter is never called which means that the bind function (setRunnable is not called).Hwever, using the console command "services" I see that the exporter bundle is used by the imporeter one. Also, using ss and ls I can see that the component eporter is "satisfied".
What is wrong with my implementetion?
Thanks in advance
Cheers
Marie
The following bind signature is not supported by any version of DS:
public void setRunnable(Runnable r, ServiceReference ref)
Instead you will have to take only the ServiceReference and use either the ComponentContext or BundleContext to access the service instance object.
Alternatively if you want a more POJO-style way of accessing service properties, the following bind signature is allowed in DS 1.1 (but not in DS 1.0):
public void setRunnable(Runnable r, Map properties)
To access DS 1.1 features, you need to add the correct namespace to your XML as follows:
<component xmlns='http://www.osgi.org/xmlns/scr/v1.1.0' name='...'>
By the way, I wrote this original article a very long time ago! These days I would use bnd annotations to avoid having to write the XML document by hand.