I am currently trying to use the ViewAccessControl Interface of vaadin.spring as explained in the last paragraph of this tutorial.
But when implementing the isAccessGranted Method I get the following error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'frontPageView': Scope 'vaadin-view' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No active view
The declaration of the FrontPageView class (The only thing I do in the enter method, is to add some vaadin ui elements):
#SpringView(name = FrontPageView.NAME)
public class FrontPageView extends DashboardDesign implements View, ViewAccessControl {
#Override
public void enter(ViewChangeEvent event) {
}
}
And my implementation of the isAccessGranted Method:
#Override
public boolean isAccessGranted(UI ui, String beanName) {
return SecurityContextHolder.getContext().getAuthentication().isAuthenticated();
}
P.S. Its basically the same problem this guy had a year ago: How to create a secure view with Vaadin and SpringViewProvider
Ok I figured it out now. If anyone else ever finds this problem, the solution is to use the ViewInstanceAccessControl interface instead of the ViewAccessControl iterface. Everything works fine this way.
Related
ATM I am in the middle of refactoring our Selenium E2E Test Framework to use Spring.
My class/bean:
package info.fingo.selenium.utils.driver;
#Component
#Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public class ProxyDecorator extends WebDriverDecorator<WebDriver> {
#Autowired
public ProxyDecorator(TestUtils testUtils, DriverManager driverManager) {
super(WebDriver.class);
this.testUtils = testUtils;
this.driverManager = driverManager;
Superclass:
package org.openqa.selenium.support.decorators;
public class WebDriverDecorator<T extends WebDriver> {
private final Class<T> targetWebDriverClass;
private Decorated<T> decorated;
#SuppressWarnings("unchecked")
public WebDriverDecorator() {
this((Class<T>) WebDriver.class);
}
public WebDriverDecorator(Class<T> targetClass) {
this.targetWebDriverClass = targetClass;
}
public final T decorate(T original) {
Require.nonNull("WebDriver", original);
decorated = createDecorated(original);
return createProxy(decorated, targetWebDriverClass);
}
Issue occures on calling this line:
createProxy(decorated, targetWebDriverClass)
Where targetWebDriverClass for unknown reason is null and NullPointerException is later thrown.
This should not EVER happen as targetWebDriverClass is ALWAYS set through constructor - either provided by client (calling super(class)) or defaulted to WebDriver.class in default WebDriverDecorator constructor. Worked fine without Spring, and unfortunately I don't understand Spring enough to get any information through debugging.
My Spring dependencies:
ext.springVersion = '2.7.1'
dependencies {
//SPRING BOOT
api "org.springframework.boot:spring-boot-starter:$springVersion",
"org.springframework.boot:spring-boot-starter-aop:$springVersion",
"org.springframework.boot:spring-boot-starter-test:$springVersion",
decorate method in superclass WebDriverDecorator in marked as final which makes it ineligible for Spring CGLIB proxying as it cannot proxy final methods (& classes) - Sorry, I don't know exact reason why this caused my issue.
This is not my own class, it is taken from inside of dependency so I cannot change this.
This means that this class cannot be managed by Spring. In order for this to somehow work I get rid of inheritance (extends keyword) and replace it with composition. Got to do some reflection magic (for one of its protected method) but this seems to do the trick.
I am having two implementations of my component.
public interface MyComponent {
}
imple1
#Component("impCompf")
#Lazy
#RequestScope
public class ImpComp1 implements MyComponent {
}
imple2
#Component("impComps")
#Lazy
#RequestScope
public class ImpComp2 implements MyComponent {
}
What I did so far is to create two conditions like so:
imple1
public class FirstCondition implements Condition {
#Override
public boolean matches(ConditionContext arg0, AnnotatedTypeMetadata arg1) {
return staticVariable.contains("impCompf");
}
}
Same goes for imple2
and define a configuration class
#Configuration
public class MyConfiguration {
#Bean
#Conditional(FirstCondition .class)
#Primary
public MyComponent getComp1() {
return new ImpComp1();
}
public static String staticVariable= "impCompf";
and in My main controller:
#RequestMapping(value="api/{co}", method=RequestMethod.POST)
public ResponseEntity<Modelx> postSe(#PathVariable("co") String co) {
if(co.contains("impCompf"))
staticVariable = "impCompf";
else (co.contains("impComps"))
staticVariable = "impComps";
What I want: for every http request I want to load proper implementation
But however what I am getting is the implementation defined first in the static variable.
If is there another elegant and better way, i'd like to know about it.
I think there is some confusion here about the purpose of the conditions. These aren't being used at the time your requests arrive to autowire the candidate bean into your controller. These are being used when the application is started to configure the application context based on the environment and classpath etc...
There is no need for the conditional classes that you have created. This is defining the configuration of the beans when the context starts and not on a per request basis at runtime.
The use of the static variable is also problematic is a scenario with one or more concurrent requests or in a case where multiple threads may observe different values unless some other mechanism in the java memory model is being used (such as volatile or establishing a happens before relationship, e.g. with sychnronized)
There are a number of ways to do what you appear to be trying to achieve. Since ultimately, you appear to be using a path parameter supplied by a client to determine which service you want to invoke you could use a classic factory pattern to return the correct interface implementation based on the string input programmatically.
Alternatively you could create two distinct controller methods which are distinguished by a query parameter or endpoint name or path match etc. You could then have the appropriate service injected by a qualified bean name
Although perhaps generally recommended, you could also inject an application context instance and search the it looking for the relevant bean by name or class: https://brunozambiazi.wordpress.com/2016/01/16/getting-spring-beans-programmatically/ - although This is more cumbersome and you'd need to handle things like org.springframework.beans.factory.NoSuchBeanDefinitionException or casting in some cases - best avoided in favour of one of the other methods.
As the title states, I'm trying to use Whiteboard to host my VaadinServlet. After many failed attempts at using other embedded servlet containers such as Jetty and Grizzly, I came across this solution here, written by the Bndtools man himself, Peter. I've tried implementing this myself, but I'm getting an error I cannot solve myself:
[test.client.ui.ClientUI$ClientServlet(4)] Error during instantiation of the implementation object
java.lang.InstantiationException: test.client.ui.ClientUI$ClientServlet: test.client.ui.ClientUI$ClientServlet.<init>()
Caused by: org.apache.felix.log.LogException: java.lang.InstantiationException: test.client.ui.ClientUI$ClientServlet
at java.lang.Class.newInstance(Class.java:427)
at org.apache.felix.scr.impl.manager.SingleComponentManager.createImplementationObject(SingleComponentManager.java:253)
at org.apache.felix.scr.impl.manager.SingleComponentManager.createComponent(SingleComponentManager.java:127)
at org.apache.felix.scr.impl.manager.SingleComponentManager.getService(SingleComponentManager.java:871)
at org.apache.felix.scr.impl.manager.SingleComponentManager.getServiceInternal(SingleComponentManager.java:838)
at org.apache.felix.scr.impl.manager.AbstractComponentManager.activateInternal(AbstractComponentManager.java:850)
at org.apache.felix.scr.impl.manager.AbstractComponentManager.enable(AbstractComponentManager.java:419)
at org.apache.felix.scr.impl.config.ConfigurableComponentHolder.enableComponents(ConfigurableComponentHolder.java:376)
at org.apache.felix.scr.impl.BundleComponentActivator.initialize(BundleComponentActivator.java:172)
at org.apache.felix.scr.impl.BundleComponentActivator.<init>(BundleComponentActivator.java:120)
at org.apache.felix.scr.impl.Activator.loadComponents(Activator.java:258)
at org.apache.felix.scr.impl.Activator.access$000(Activator.java:45)
at org.apache.felix.scr.impl.Activator$ScrExtension.start(Activator.java:185)
at org.apache.felix.utils.extender.AbstractExtender.createExtension(AbstractExtender.java:259)
at org.apache.felix.utils.extender.AbstractExtender.modifiedBundle(AbstractExtender.java:232)
... 17 more
Caused by: java.lang.NoSuchMethodException: test.client.ui.ClientUI$ClientServlet.<init>()
at java.lang.Class.getConstructor0(Class.java:3082)
at java.lang.Class.newInstance(Class.java:412)
at org.apache.felix.scr.impl.manager.SingleComponentManager.createImplementationObject(SingleComponentManager.java:253)
at org.apache.felix.scr.impl.manager.SingleComponentManager.createComponent(SingleComponentManager.java:127)
at org.apache.felix.scr.impl.manager.SingleComponentManager.getService(SingleComponentManager.java:871)
at org.apache.felix.scr.impl.manager.SingleComponentManager.getServiceInternal(SingleComponentManager.java:838)
at org.apache.felix.scr.impl.manager.AbstractComponentManager.activateInternal(AbstractComponentManager.java:850)
at org.apache.felix.scr.impl.manager.AbstractComponentManager.enable(AbstractComponentManager.java:419)
at org.apache.felix.scr.impl.config.ConfigurableComponentHolder.enableComponents(ConfigurableComponentHolder.java:376)
at org.apache.felix.scr.impl.BundleComponentActivator.initialize(BundleComponentActivator.java:172)
at org.apache.felix.scr.impl.BundleComponentActivator.<init>(BundleComponentActivator.java:120)
at org.apache.felix.scr.impl.Activator.loadComponents(Activator.java:258)
at org.apache.felix.scr.impl.Activator.access$000(Activator.java:45)
at org.apache.felix.scr.impl.Activator$ScrExtension.start(Activator.java:185)
at org.apache.felix.utils.extender.AbstractExtender.createExtension(AbstractExtender.java:259)
... 18 more
I added empty constructors just for the hell of it to see if they changed anything but nope.
ClientUI and ClientServlet classes:
public class ClientUI extends UI
{
public ClientUI()
{
//Empty constructor.
}
#Override
public void init(VaadinRequest request)
{
//Typical UI initialization.
}
}
#VaadinServletConfiguration(productionMode = false, ui = ClientUI.class)
#Component(provide = Servlet.class, properties = {"alias=/test"}, immediate = true)
public class ClientServlet extends VaadinServlet
{
// Empty class. This class uses the annotations for servlet configuration instead of a web.xml.
public ClientServlet()
{
// Empty constructor.
}
}
Any idea on how to stop this error and get the servlet up and running?
Edit: New error! Steffen, who commented below, pointed out I may have needed to move the servlet class to a top-level class, in which I most likely did need to, but now I get this:
org.osgi.framework.ServiceException: Service cannot be cast: javax.servlet.Servlet
Caused by: org.apache.felix.log.LogException: org.osgi.framework.ServiceException: Service cannot be cast: javax.servlet.Servlet
at org.apache.felix.framework.ServiceRegistrationImpl.getFactoryUnchecked(ServiceRegistrationImpl.java:344)
at org.apache.felix.framework.ServiceRegistrationImpl.getService(ServiceRegistrationImpl.java:231)
at org.apache.felix.framework.ServiceRegistry.getService(ServiceRegistry.java:327)
at org.apache.felix.framework.Felix.getService(Felix.java:3574)
at org.apache.felix.framework.BundleContextImpl.getService(BundleContextImpl.java:468)
at org.osgi.util.tracker.ServiceTracker.addingService(ServiceTracker.java:411)
at org.apache.felix.http.whiteboard.internal.tracker.AbstractTracker.addingService(AbstractTracker.java:35)
at org.osgi.util.tracker.ServiceTracker$Tracked.customizerAdding(ServiceTracker.java:932)
at org.osgi.util.tracker.ServiceTracker$Tracked.customizerAdding(ServiceTracker.java:864)
at org.osgi.util.tracker.AbstractTracked.trackAdding(AbstractTracked.java:256)
at org.osgi.util.tracker.AbstractTracked.track(AbstractTracked.java:229)
at org.osgi.util.tracker.ServiceTracker$Tracked.serviceChanged(ServiceTracker.java:894)
at org.apache.felix.framework.util.EventDispatcher.invokeServiceListenerCallback(EventDispatcher.java:943)
at org.apache.felix.framework.util.EventDispatcher.fireEventImmediately(EventDispatcher.java:794)
at org.apache.felix.framework.util.EventDispatcher.fireServiceEvent(EventDispatcher.java:544)
... 12 more
Also, this question may eventually be deleted. I'm looking at this Vaadin/OSGi EnRoute example that does what I need and I have confirmed that it works. I may just use the example provider and API for an application or create something similar. I will leave this question up for now just to provide to the knowledge of the internet and see if anyone can answer!
I have used Spring in the past. I moved to a different team where I am getting familiarized with codebase. I found the following code and trying to understand how it works and how spring injects autowired objects in the case. From my basics of Spring, this is definitely not the right way to do. But surprisingly, this code is in production for a long time and no issues were identified.
#Controller
#RequestMapping("/start")
public class AController implements Runnable, InitializingBean {
#Autowired
private StartServiceImpl service = new StartServiceImpl(); // 1
Thread thread;
public void run() {
service.start();
}
public void stop() {
try {
thread.join();
} catch (InterruptedException e) {
}
}
}
#Override
public void afterPropertiesSet() throws Exception {
thread = new Thread(this);
thread.setPriority(Thread.MAX_PRIORITY);
thread.start();
}
}
#Component
public class StartServiceImpl {
//methods
}
Q1) What does localhost:8080/project/start is expected to do. There is NO GET or POST methods defined.
Q2) on the commented line 1, StartServiceImpl is both autowired and constructed with "new". So what happens here. Does the container inject bean or just an object is instantiated.
#Controller
#RequestMapping("/stop")
public class BController {
#Autowired
private StartServiceImpl service = new StartServiceImpl();
#RequestMapping(value = "**", method = RequestMethod.GET)
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
service.shutdownRequested();
new AController().stop(); // 2
} catch (Exception e) {
}
}
}
Q3) Again in commented line 2, does calling stop, calls the stop on the bean in the application context or a new object gets created and the stop method is called. What would happen in the latter case? Are we really stopping the service that was started or not? I think we are not stopping the service.
I have read this post. It is very useful. But it did not answer my question.
I will try to answer the questions specifically, as the purpose of the code is hard to understand (for me at least).
Q1) It is unclear for me what this code tries to achieve. As you noticed, it is not a controller, and I suspect that the only reason why it is registered this way is so that it gets auto-scanned (which might as well get done by using #Controller. This is just a hunch, I don't quite understand its purpose.
Q2) The answer is that two instances will be created, one via new, the other as a bean. When running in Spring, the final value of the field is the bean, because dependency injection happens after the construction. Typically this is done when the class is envisioned to be used outside Spring (e.g. a unit test), so that the field can be initialized with a default value.
Q3) stop() will be invoked on a new instance, and not the bean. The service bean is stopped because of the direct call above that line to the injected bean, but the next one will be an NPE, I guess, because afterPropertiesSet is not invoked on the target object created via new. the only reason why this doesn't show an NPE in the logs is because the exception is swallowed below. The thread variable is not initialized and remains NULL.
Hope this helps,
This code is flawed on many levels.
Ever since Java 5, manually starting threads is an antipattern. It's messy and way too low-level. ExecutorServices should be used.
A Rest controller that is a Runnable? That's a monstrous mingling of concerns.
A service is created via new but then overwritten with an autowired dependency? WTF!
etc.
I'd keep the thread running all the time, scheduling the task with the #Scheduled annotation and use the controller to toggle a flag that decides if the thread actually does somethin, e.g.
#Service
class StartService{
private boolean active;
public void setActive(boolean active){this.active=active;}
#Scheduled(fixedRate=5000)
public void doStuff(){
if(!active)return;
// do actual stuff here
}
}
And now all the rest controllers do is toggle the value of the "active" field. Benefits:
every class does one thing only
you always know how many threads you have
The code you posted is very strange.
Q1 ) What does localhost:8080/project/start is expected to do. There
is NO GET or POST methods defined.
I think localhost:8080/project/start will return 404 error (The requested resource is not available). Because there is no mapped methods in AController. #RequestMapping annotation on class level is not enough for make request to controller. There is have to be mapped method.
But service will be started anyway. Because AController implements InitializingBean. Method afterPropertiesSet() will be invoked by Spring after controller will be created and all fields will be initialized.
Q2) on the commented line 1, StartServiceImpl is both autowired and
constructed with "new". so what happens here. does the container
inject bean or just an object is instantiated.
Another strange snippet. Java will create new instance of StartServiceImpl on creation of instance of AController class. But after that, Spring will assign it's own instance(declared as component) to this field. And reference to firs instance (created by constructor) will be lost.
Q3) Again in commented line 2, does calling stop, calls the stop on
the bean in the appication context or a new object gets created and
the stop method is called. what would happen in the latter case? Are
we really stopping the service that was started or not? I think we are
not stopping the service
Actually service will be stopped. Because of invocation of service.shutdownRequested();. But thread in AController bean will continue to work. new AController().stop(); will invoke method of just created instance, but not method of controller (instance created by Spring).
This code is totally wrong usage of Spring framework.
I am writing tests for my wicket-application and need to inject a Spring Bean into a page (done by annotation) to do this.
Consider following code:
protected void setUp() {
tester = new WicketTester();
scanService = new ScanService();
ApplicationContextMock appctx=new ApplicationContextMock();
appctx.putBean("pxGenericService", new PxGenericServiceImpl());
tester.getApplication().getComponentInstantiationListeners().add(new SpringComponentInjector(tester.getApplication(), appctx));
}
This actually seem to work (no nullpointer). The problem is: the bean got a resource (variable with #Resource annotation) and when I run the test on the page, this resource turns out to be null (nullpointer exception). How do I fix this problem?
You also have to add an instance of all dependencies your bean has to the mock application context. So add an instance of the class PxGenericServiceImpl uses to appctx.
I don't think that SpringComponentInjector supports #Resource. The only supported annotations are #SpringBean and #Inject. See AnnotProxyFieldValueFactory:
#Override
public boolean supportsField(final Field field)
{
return field.isAnnotationPresent(SpringBean.class) || field.isAnnotationPresent(Inject.class);
}