Unexpected Vaadin Session Expired and parallel spring boot applications - spring

I am using Vaadin 8.9.4 and Spring boot 2.2.4.RELEASE. I have 2 spring boot applications, FirstApplication (server.port=8083) and SecondApplication (server.port=8084). Both the application have #SpringUI annotated class extending UI Class, as given below. The session for FirstApplication is expired as soon as I click on the button in the SecondApplication and vice versa. This happens only when I use two chorme tabs in parallel. If I use two different browsers, everything is working as expected.
Is this some kind of a bug as I expect no relation between the sessions of the two applications simply because they are running independently on different port.
Note: I am new to the spring boot and I am trying to build 2 micorservices communicating with each other via Rest API.
#SpringUI
#Theme("valo")
public class FirstApplicationUI extends UI {
private static final long serialVersionUID = 9197592298697220144L;
#Override
protected void init(final VaadinRequest request) {
final VerticalLayout layout = new VerticalLayout();
final Label label = new Label("First Application");
final Button button = new Button("click");
button.addClickListener(e -> Notification.show("First Application"));
layout.addComponents(label, button);
setContent(layout);
}
}
#SpringUI
#Theme("valo")
public class SecondApplicationUI extends UI {
private static final long serialVersionUID = 9059755286859361908L;
#Override
protected void init(final VaadinRequest request) {
final VerticalLayout layout = new VerticalLayout();
final Label label = new Label("Second Application");
final Button button = new Button("click");
button.addClickListener(e -> Notification.show("Second Application"));
layout.addComponents(label, button);
setContent(layout);
}
}

This is your two applications battling over the same cookie; both use the same name and your browser happily sends both backends the same cookie as the port is not considered.
Change the name in at least one of your applications; see server.servlet.session.cookie.name in https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html

Related

Pushing Images Vaadin Java

i am trying to create a turn-base card game in Vaadin-Java, everything was going well so far, but i have a problem with pushing Vaadin Images to other UI. I did copy Broadcast/BroadcasterView Class from Vaadin Documentation and it works as intended, but not for images.
public class Broadcaster {
static Executor executor = Executors.newSingleThreadExecutor();
static LinkedList<Consumer<String>> listeners = new LinkedList<>();
public static synchronized Registration register(
Consumer<String> listener) {
listeners.add(listener);
return () -> {
synchronized (Broadcaster.class) {
listeners.remove(listener);
}
};
}
public static synchronized void broadcast(String message) {
for (Consumer<String> listener : listeners) {
executor.execute(() -> listener.accept(message));
}
}
}
#Push
#Route("broadcaster")
public class BroadcasterView extends Div {
VerticalLayout messages = new VerticalLayout();
Registration broadcasterRegistration;
// Creating the UI shown separately
#Override
protected void onAttach(AttachEvent attachEvent) {
UI ui = attachEvent.getUI();
broadcasterRegistration = Broadcaster.register(newMessage -> {
ui.access(() -> messages.add(new Span(newMessage)));
});
}
#Override
protected void onDetach(DetachEvent detachEvent) {
broadcasterRegistration.remove();
broadcasterRegistration = null;
}
}
public BroadcasterView() {
TextField message = new TextField();
Button send = new Button("Send", e -> {
Broadcaster.broadcast(message.getValue());
message.setValue("");
});
HorizontalLayout sendBar = new HorizontalLayout(message, send);
add(sendBar, messages);
}
the code above works fine for Strings, Vaadin Icons etc, but when i replace for and naturally change the broadcast method, there is no reaction.
i've searched for the solution throughout the internet, but it seems, people don't need to push images or it's simply not possible here. I thought that this is perhaps the matter of payload, but it doesn't work even for 5px x 5px images
perhaps one of You have encountered such problem and found solution?
You need to pass data through the broadcaster, but what you write about your attempts makes me suspect that you've been trying to pass UI components (i.e. instances of com.vaadin.flow.component.html.Image). That won't work because a UI component instance cannot be attached to multiple locations (i.e. multiple browser windows in this case) at the same time.
What you can try is to pass the data (e.g. a String with the image URL) through the broadcaster and then let each subscriber create their own Image component based on the data that they receive.

Custom JASPIC on WebSphere error message

Though similar, the specific problem I have is not addressed in Use JASPIC auth module on WebSphere 8.5
I am getting the following error message:
SECJ8027E: The path and name of file where JASPI persistent registrations are stored must be specified using property com.ibm.websphere.jaspi.configuration.
I can set the custom property in the administration to some existing folder but I wanted to make sure that is the right approach or if there is some step I was missing.
Note I am specifically using the "embedded in application" approach rather than a server installed JASPIC module so I have something like this
#WebListener
public class JaspicInitializer implements
ServletContextListener {
#Override
public void contextInitialized(final ServletContextEvent sce) {
final Map<String, String> options = new HashMap<>();
AuthConfigFactory.getFactory()
.registerConfigProvider(AuthModuleConfigProvider.class.getName(), options, "HttpServlet", null, null);
}
}
I had the error on both WebSphere 8.5.5.11 and 9.0.0.3
From #Uux comment, I changed the way I do the registration so it no longer give the error.
#WebListener
public class JaspicInitializer implements
ServletContextListener {
private String registrationID;
#Override
public void contextDestroyed(final ServletContextEvent sce) {
AuthConfigFactory.getFactory().removeRegistration(registrationID);
}
#Override
public void contextInitialized(final ServletContextEvent sce) {
final ServletContext context = sce.getServletContext();
registrationID = AuthConfigFactory.getFactory()
.registerConfigProvider(new AuthModuleConfigProvider(), "HttpServlet",
context.getVirtualServerName() + " " + context.getContextPath(), "JEE Sample");
}
}
Also WebSphere Global Security needs to be configured with
Enable application security
Enable Java Authentication SPI (JASPI)

Activator.updated() method is not called in osgi

I am using Apache Felix for osgi. Other bundles are running just fine. I've add new bundle to the reactor. The Activator.init() method is called. But I will never get into the updated() method. Any ideas?
public class Activator extends DependencyActivatorBase implements ManagedServiceFactory {
private static final Logger logger = LoggerFactory.getLogger(Activator.class);
public static final String PID = "my.unique.pid";
private final Map<String, Component> components = new HashMap<>();
private volatile DependencyManager dependencyManager; /* injected by dependency manager */
#Override
public void init(BundleContext bc, DependencyManager dm) throws Exception {
Properties props = new Properties();
props.put(Constants.SERVICE_PID, PID);
dm.add(createComponent()
.setInterface(ManagedServiceFactory.class.getName(), props)
.setImplementation(this)
.add(createConfigurationDependency().setPid(PID))
);
dm.add(createComponent()
.setInterface(SessionRegister.class.getName(), null)
.setImplementation(SessionRegisterImpl.class)
);
dm.add(createComponent()
.setInterface(Plugin.class.getName(), null)
.setImplementation(PriorityActionHandler.class)
.add(createServiceDependency().setRequired(true).setService(PluginManager.class))
);
}
#Override
public void updated(String pid, Dictionary<String, ?> properties) throws ConfigurationException {
logger.debug("This method should be called and run!");
if (properties == null) {
logger.warn("Configuration is empty!");
return;
}
.
.
.
}
The init method is likely not what you intended. You create a component that is a ManagedServiceFactory, with a PID, and you also make that same component have a service dependency (which translates to making it a ManagedService, with the same PID, which is not allowed and definitely confusing). I am assuming you meant either of these two.
The updated method you have right now assumes you wanted to be a ManagedServiceFactory and there updated will be invoked for each configuration (one or more) that you provide. From your code I cannot see if you have an implementation of Configuration Admin installed and if you actually somehow provide one or more configurations for this PID.
Please provide more information to further pinpoint this issue if this answer does not help you yet.

Intermittent issue with Remote EJB invocation on WAS 7.0

We have a business functionality which is exposed as a Remote EJB. We shared the remote interface with the client. Below is the Remote interface that we shared.
public interface EmployeeRemoteEJB {
public Output saveEmployee(Input input);
}
public Output extends BaseObj{
private static final long serialVersionUID = -7096731222829800554L;
//some fields are there
}
public Input extends BaseObj{
private static final long serialVersionUID = -70967312228423800554L;
//some fields
}
public BaseObj implements Serializable{
}
Now Input class and Output class has some fields, which also extends from BaseObj and has a generated SerialVersion UID.
Now we have deployed this EJB on WebSphere Application Server 7.0. The Remote invocation of EJB works fine. It breaks when we do a deployment of the Client web app which calls the EJB or the
web application which has the EJB. We get the ClassCastException that the
com.test.ejb._EmployeeRemoteEJB_Stub incompatible with com.test.ejb.EmployeeRemoteEJB
When we restart the applications, it starts working again.
This is how we invoke the Remote EJB
//This JNDI name is configured for the remote EJB.
String REMOTE_LOOKUP_KEY = "empremotesvc";
String JNDI_PROVIDER_URL = "iiop://10.222.232.111:2809";
Properties props = new Properties();
props.put( Context.INITIAL_CONTEXT_FACTORY,"com.ibm.websphere.naming.WsnInitialContextFactory");
props.put( Context.PROVIDER_URL, JNDI_PROVIDER_URL );
Object lobj;
InitialContext ctx;
try{
ctx = new InitialContext( props );
lobj = ctx.lookup( REMOTE_LOOKUP_KEY );
EmployeeRemoteEJB empObjRemote = (EmployeeRemoteEJB) lobj;
return empObjRemote ;
}
catch( NamingException e ){
e.printStackTrace();
}
Can someone please let me know what is causing this issue? Please let me know if you need any further details.
You need to call PortableRemoteObject.narrow:
lobj = ctx.lookup( REMOTE_LOOKUP_KEY );
EmployeeRemoteEJB empObjRemote = (EmployeeRemoteEJB)
PortableRemoteObject.narrow(lobj, EmployeeRemoteEJB.class);
The problem does not always occur because JNDI caches resolved IOR-to-stub using the class loader of first client app to look up the EJB, so the first application to use the target EJB will work, but the second and subsequent will not unless they use PortableRemoteObject.narrow.

ApacheConnector does not process request headers that were set in a WriterInterceptor

I am experiencing problems when configurating my Jersey Client with the ApacheConnector. It seems to ignore all request headers that I define in a WriterInterceptor. I can tell that the WriterInterceptor is called when I set a break point within WriterInterceptor#aroundWriteTo(WriterInterceptorContext). Contrary to that, I can observe that the modification of an InputStream is preserved.
Here is a runnable example demonstrating my problem:
public class ApacheConnectorProblemDemonstration extends JerseyTest {
private static final Logger LOGGER = Logger.getLogger(JerseyTest.class.getName());
private static final String QUESTION = "baz", ANSWER = "qux";
private static final String REQUEST_HEADER_NAME_CLIENT = "foo-cl", REQUEST_HEADER_VALUE_CLIENT = "bar-cl";
private static final String REQUEST_HEADER_NAME_INTERCEPTOR = "foo-ic", REQUEST_HEADER_VALUE_INTERCEPTOR = "bar-ic";
private static final int MAX_CONNECTIONS = 100;
private static final String PATH = "/";
#Path(PATH)
public static class TestResource {
#POST
public String handle(InputStream questionStream,
#HeaderParam(REQUEST_HEADER_NAME_CLIENT) String client,
#HeaderParam(REQUEST_HEADER_NAME_INTERCEPTOR) String interceptor)
throws IOException {
assertEquals(REQUEST_HEADER_VALUE_CLIENT, client);
// Here, the header that was set in the client's writer interceptor is lost.
assertEquals(REQUEST_HEADER_VALUE_INTERCEPTOR, interceptor);
// However, the input stream got gzipped so the WriterInterceptor has been partly applied.
assertEquals(QUESTION, new Scanner(new GZIPInputStream(questionStream)).nextLine());
return ANSWER;
}
}
#Provider
#Priority(Priorities.ENTITY_CODER)
public static class ClientInterceptor implements WriterInterceptor {
#Override
public void aroundWriteTo(WriterInterceptorContext context)
throws IOException, WebApplicationException {
context.getHeaders().add(REQUEST_HEADER_NAME_INTERCEPTOR, REQUEST_HEADER_VALUE_INTERCEPTOR);
context.setOutputStream(new GZIPOutputStream(context.getOutputStream()));
context.proceed();
}
}
#Override
protected Application configure() {
enable(TestProperties.LOG_TRAFFIC);
enable(TestProperties.DUMP_ENTITY);
return new ResourceConfig(TestResource.class);
}
#Override
protected Client getClient(TestContainer tc, ApplicationHandler applicationHandler) {
ClientConfig clientConfig = tc.getClientConfig() == null ? new ClientConfig() : tc.getClientConfig();
clientConfig.property(ApacheClientProperties.CONNECTION_MANAGER, makeConnectionManager(MAX_CONNECTIONS));
clientConfig.register(ClientInterceptor.class);
// If I do not use the Apache connector, I avoid this problem.
clientConfig.connector(new ApacheConnector(clientConfig));
if (isEnabled(TestProperties.LOG_TRAFFIC)) {
clientConfig.register(new LoggingFilter(LOGGER, isEnabled(TestProperties.DUMP_ENTITY)));
}
configureClient(clientConfig);
return ClientBuilder.newClient(clientConfig);
}
private static ClientConnectionManager makeConnectionManager(int maxConnections) {
PoolingClientConnectionManager connectionManager = new PoolingClientConnectionManager();
connectionManager.setMaxTotal(maxConnections);
connectionManager.setDefaultMaxPerRoute(maxConnections);
return connectionManager;
}
#Test
public void testInterceptors() throws Exception {
Response response = target(PATH)
.request()
.header(REQUEST_HEADER_NAME_CLIENT, REQUEST_HEADER_VALUE_CLIENT)
.post(Entity.text(QUESTION));
assertEquals(200, response.getStatus());
assertEquals(ANSWER, response.readEntity(String.class));
}
}
I want to use the ApacheConnector in order to optimize for concurrent requests via the PoolingClientConnectionManager. Did I mess up the configuration?
PS: The exact same problem occurs when using the GrizzlyConnector.
After further research, I assume that this is rather a misbehavior in the default Connector that uses a HttpURLConnection. As I explained in this other self-answered question of mine, the documentation states:
Whereas filters are primarily intended to manipulate request and
response parameters like HTTP headers, URIs and/or HTTP methods,
interceptors are intended to manipulate entities, via manipulating
entity input/output streams
A WriterInterceptor is not supposed to manipulate the header values while a {Client,Server}RequestFilter is not supposed to manipulate the entity stream. If you need to use both, both components should be bundled within a javax.ws.rs.core.Feature or within the same class that implements two interfaces. (This can be problematic if you need to set two different Prioritys though.)
All this is very unfortunate though, since JerseyTest uses the Connector that uses a HttpURLConnection such that all my unit tests succeeded while the real life application misbehaved since it was configured with an ApacheConnector. Also, rather than suppressing changes, I wished, Jersey would throw me some exceptions. (This is a general issue I have with Jersey. When I for example used a too new version of the ClientConnectionManager where the interface was renamed to HttpClientConnectionManager I simply was informed in a one line log statement that all my configuration efforts were ignored. I did not discover this log statement til very late in development.)

Resources