Passing more than one object to an EJB remote interface - rmi

I am trying to pass more than object to an EJB remote interface deployed no Glassfish 3.1.1. Whatever is the first object it will pass fine the second object is always null. Is it due to the specs of rmi-iiop or is it a property setting?
Here is my property settings:
final Properties props = new Properties();
props.setProperty(InitialContext.STATE_FACTORIES,
"com.sun.enterprise.naming.SerialInitContextFactory");
props.setProperty("java.naming.factory.url.pkgs",
"com.sun.enterprise.naming");
props.setProperty("java.naming.factory.state",
"com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl");
props.setProperty("org.omg.CORBA.ORBInitialHost", "192.168.1.192");
props.setProperty("org.omg.CORBA.ORBInitialPort", "3700");
// props.setProperty("com.sun.appserv.iiop.orbconnections","5");
// Increase ORB Response Timeout to 5 min instead of 30 min:
// props.setProperty("com.sun.corba.ee.transport.ORBTCPTimeouts",
// "500:90000:20");
props.setProperty(
"com.sun.corba.ee.transport.ORBWaitForResponseTimeout",
"300000");
try {
InitialContext ic=new InitialContext(props);
TestRemote remote=(TestRemote) ic.lookup("java:global/com.capmtech_test.ear-ear_ear_1.0-SNAPSHOT/test.ear-ejb-1.0-SNAPSHOT/Test!com.capmtech.TestRemote");
Person p = new Person();
p.setName("Smith");
Phone m = new Phone();
remote.test(p, m);
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Here is the stateless EJB:
#Stateless
public class Test implements TestRemote {
#EJB
private PersonFacadeLocal personFacade;
#Override
public void test(Person person, Phone mobile) {
Person p = person;
p.setMobile(mobile);
personFacade.create(p);
}
// Add business logic below. (Right-click in editor and choose
// "Insert Code > Add Business Method")
}
In this case mobile will always be null, if I swap the aruguments person would be null! If the IP was set to localhost everything would work fine.
Please help

This is all assuming you are running your glassfish server and the standalone client on the same machine. I am able to reproduce a problem in this area. While it is not exactly your problem, you may get results with the same changes. I am running GF 3.1 on Windows Vista. My windows\system32\drivers\etc\hosts file has the following lines:
10.99.0.199 pc-2017.pgx.local
127.0.0.1 localhost pc-2017.pgx.local
When my client software connects with:
props.put("org.omg.CORBA.ORBInitialHost", "localhost");
I get the error:
Exception in thread "main" javax.ejb.EJBException: java.rmi.RemoteException: CORBA INTERNAL 1330446421 No; nested exception is:
org.omg.CORBA.INTERNAL: ----------BEGIN server-side stack trace----------
org.omg.CORBA.INTERNAL: WARNING: IOP00710085: A reflective tie got an error while invoking method saveMonkey on class com.pts.monkey._MonkeySessionRemote_Remote
vmcid: OMG minor code: 85 completed: No
but then if I change the client to connect with:
props.put("org.omg.CORBA.ORBInitialHost", "pc-2017.pgx.local");
it works correctly.

replace the following lines:
props.setProperty("org.omg.CORBA.ORBInitialHost", "192.168.1.192");
props.setProperty("org.omg.CORBA.ORBInitialPort", "3700");
with:
props.setProperty(Context.PROVIDER_URL,"iiop://192.168.1.192:3700");

Related

Add a self hosted SignalR server to a .Net Core Worker Service

I'm trying to extend a .NET Core Worker Service (<Project Sdk="Microsoft.NET.Sdk.Worker">) with SignalR (self hosted web app).
All the examples/tutorials/docs I have found are based on web applications, so they don't fit my case.
This is what I've done until now:
MyService Program.cs:
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseWindowsService()
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<Worker>();
DependencyBuilder.Build(hostContext, services); // inject the stuff I need in my service
// create a SignalR Web host
SignalRWebHostCreator.CreateHost(services, "http://localhost:8090", (endpoints) => {
endpoints.MapHub<MyHub>("/result");
});
});
}
and the class I want to use to "extend" the servie with a SignalR server application.
public class SignalRWebHostCreator
{
public static void CreateHost(IServiceCollection services, string serviceUrl, Action<IEndpointRouteBuilder> mapHubs)
{
services.AddSignalR(); // is it ok here ?
WebHost.CreateDefaultBuilder()
.UseUrls(serviceUrl)
.Configure((IApplicationBuilder app) => {
app.UseRouting();
app.Map("/check", config => { // just a test: it works!
config.Run(async context =>
{
context.Response.ContentType = "text/plain";
byte[] data = System.Text.Encoding.UTF8.GetBytes("OK");
await context.Response.Body.WriteAsync(data, 0, data.Length);
await context.Response.Body.FlushAsync();
});
});
app.UseEndpoints(endpoints =>
{
//endpoints.MapHub<ClockHub>("/hubs/clock"); // ERROR
//endpoints.MapHub<PingHub>("/ping"); // ERROR
//mapHubs(endpoints); // ERROR
});
})
.Build().Run();
}
}
(ClockHub is taken from MS example and PingHub is another simple Hub I tried to use instead of my "injected" Hubs)
It starts the web application properly and it responds properly to the url http://localhost:8090/check.
When I uncomment the calls to enpoint.MapHub() or my cusom Actions I have this error:
System.InvalidOperationException: 'Unable to find the required services. Please add all the required services by calling 'IServiceCollection.AddSignalR' inside the call to 'ConfigureServices(...)' in the application startup code.'
2nd try:
Seems like service.AddSignalR() is not doing its job, so I added this in SignalRWebHostCreator:
.Configure((IApplicationBuilder app) => {
app.ApplicationServices = services.BuildServiceProvider();
and now I have this error:
System.InvalidOperationException: 'Unable to resolve service for type 'System.Diagnostics.DiagnosticListener' while attempting to activate 'Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware'.'
that at least has a callstack:
_This exception was originally thrown at this call stack:
Microsoft.Extensions.Internal.ActivatorUtilities.ConstructorMatcher.CreateInstance(System.IServiceProvider)
Microsoft.Extensions.Internal.ActivatorUtilities.CreateInstance(System.IServiceProvider, System.Type, object[])
Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.UseMiddleware.AnonymousMethod__0(Microsoft.AspNetCore.Http.RequestDelegate)
Microsoft.AspNetCore.Builder.ApplicationBuilder.Build()
Microsoft.AspNetCore.Hosting.WebHost.BuildApplication()
Microsoft.AspNetCore.Hosting.WebHost.StartAsync(System.Threading.CancellationToken)
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()_
If I add services.AddSingleton(new System.Diagnostics.DiagnosticListener("diagnostic listener")); I can use endpoints.MapHub(..) without errors but now a call to http://8090/check returns a 500 internal error, so I don't think this is the right way to solve the issue.
I found some example using WebApp from Microsoft.Owin.hosting.
It requires Microsoft.Owin.4.1.0, Microsoft.Owin.Hosting.4.1.0 and Owin.1.0.0 and the last one require Net Framework 4.6.1, I don't want this.
I have included Microsoft.AspNetCore.Owin.3.1.2 (100% .NET Core) but that does not offer WebApp or something similar.
I started experiencing same error when I upgraded nuget EFCore package to new version.
I noticed, that in my bin directory, a System.Diagnostics.DiagnosticSource.dll appeared, while when I downgraded - it disappeared.
I suspect, that DiagnosticListener type from old assembly version is registered in DI container, while on activation newer version is expected. Or reverse - I didn't dig that deep.
My solution was to revert EFCore to match Product version of System.Diagnostics.DiagnosticSource.dll so it will not appear in bin folder.

Pattern for using properly MongoClient in Vert.x

I feel quite uncomfortable with the MongoClient class, certainly because I don't exactly understand what it is and how it works.
The first call to MongoClient.createShared will actually create the
pool, and the specified config will be used.
Subsequent calls will return a new client instance that uses the same
pool, so the configuration won’t be used.
Does that mean that the pattern should be:
In startup function, to create the pool, we make a call
mc = MongoClient.createShared(vx, config, "poolname");
Is the returned value mc important for this first call if it succeeds? What is its value if the creation of the pool fails? The documentations doesn't say. There is a socket exception if mongod is not running, but what about the other cases?
In another place in the code (another verticle, for example), can we write mc = MongoClient.createShared(vx, new JsonObject(), "poolname"); to avoid to systematically need to access shared objects.
Again, In another verticle where we need to access the database, should we define MongoClient mc
as a class field in which case it will be released to the pool only in the stop() method, or
shouldn't it be a variable populated with MongoClient.createShared(...) and de-allocated with mc.close() once we don't need the connection any more in order release it again to the pool ?
What I would write is as follows
// Main startup Verticle
import ...
public class MainVerticle extends AbstractVerticle {
...
#Override
public void start(Future<Void> sf) throws Exception {
...
try {
MongoClient.createShared(vx, config().getJsonObject("mgcnf"), "pool");
}
catch(Exception e) {
log.error("error error...");
sf.fail("failure reason");
return;
}
...
sf.complete();
}
...some other methods
}
and then, in some other place
public class SomeVerticle extends AbstractVerticle {
public void someMethod(...) {
...
// use the database:
MongoClient mc = MongoClient.createShared(vx, new JsonObject(), "pool");
mc.save(the_coll, the_doc, res -> {
mc.close();
if(res.succeeded()) {
...
}
else {
...
}
}
...
}
...
}
Does that make sense ? Yet, this is not what is in the examples that I could find around the internet.
Don't worry about pools. Don't use them. They don't do what you think they do.
In your start method of any verticle, set a field (what you call a class field, but you really mean instance field) on the inheritor of AbstractVerticle to MongoClient.createShared(getVertx(), config). Close the client in your stop method. That's it.
The other exceptions you'll see are:
Bad username/password
Unhealthy cluster state
The Java driver has a limit of 500 or 1,000 connections (depending on version), you'll receive an exception if you exceed this connection count
Both will be propagated up from the driver wrapped in a VertxException.

Swagger documentation with JAX-RS Jersey 2 and Grizzly

I have implementated a Rest web service (the function is not relevant) using JAX-RS. Now I want to generate its documentation using Swagger. I have followed these steps:
1) In build.gradle I get all the dependencies I need:
compile 'org.glassfish.jersey.media:jersey-media-moxy:2.13'
2) I documentate my code with Swagger annotations
3) I hook up Swagger in my Application subclass:
public class ApplicationConfig extends ResourceConfig {
/**
* Main constructor
* #param addressBook a provided address book
*/
public ApplicationConfig(final AddressBook addressBook) {
register(AddressBookService.class);
register(MOXyJsonProvider.class);
register(new AbstractBinder() {
#Override
protected void configure() {
bind(addressBook).to(AddressBook.class);
}
});
register(io.swagger.jaxrs.listing.ApiListingResource.class);
register(io.swagger.jaxrs.listing.SwaggerSerializers.class);
BeanConfig beanConfig = new BeanConfig();
beanConfig.setVersion("1.0.2");
beanConfig.setSchemes(new String[]{"http"});
beanConfig.setHost("localhost:8282");
beanConfig.setBasePath("/");
beanConfig.setResourcePackage("rest.addressbook");
beanConfig.setScan(true);
}
}
However, when going to my service in http://localhost:8282/swagger.json, I get this output.
You can check my public repo here.
It's times like this (when there is no real explanation for the problem) that I throw in an ExceptionMapper<Throwable>. Often with server related exceptions, there are no mappers to handle the exception, so it bubbles up to the container and we get a useless 500 status code and maybe some useless message from the server (as you are seeing from Grizzly).
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
public class DebugMapper implements ExceptionMapper<Throwable> {
#Override
public Response toResponse(Throwable exception) {
exception.printStackTrace();
if (exception instanceof WebApplicationException) {
return ((WebApplicationException)exception).getResponse();
}
return Response.serverError().entity(exception.getMessage()).build();
}
}
Then just register with the application
public ApplicationConfig(final AddressBook addressBook) {
...
register(DebugMapper.class);
}
When you run the application again and try to hit the endpoint, you will now see a stacktrace with the cause of the exception
java.lang.NullPointerException
at io.swagger.jaxrs.listing.ApiListingResource.getListingJson(ApiListingResource.java:90)
If you look at the source code for ApiListingResource.java:90, you will see
Swagger swagger = (Swagger) context.getAttribute("swagger");
The only thing here that could cause the NPE is the context, which scrolling up will show you it's the ServletContext. Now here's the reason it's null. In order for there to even be a ServletContext, the app needs to be run in a Servlet environment. But look at your set up:
HttpServer server = GrizzlyHttpServerFactory
.createHttpServer(uri, new ApplicationConfig(ab));
This does not create a Servlet container. It only creates an HTTP server. You have the dependency required to create the Servlet container (jersey-container-grizzly2-servlet), but you just need to make use of it. So instead of the previous configuration, you should do
ServletContainer sc = new ServletContainer(new ApplicationConfig(ab));
HttpServer server = GrizzlyWebContainerFactory.create(uri, sc, null, null);
// you will need to catch IOException or add a throws clause
See the API for GrizzlyWebContainerFactory for other configuration options.
Now if you run it and hit the endpoint again, you will see the Swagger JSON. Do note that the response from the endpoint is only the JSON, it is not the documentation interface. For that you need to use the Swagger UI that can interpret the JSON.
Thanks for the MCVE project BTW.
Swagger fixed this issue in 1.5.7. It was Issue 1103, but the fix was rolled in last February. peeskillet's answer will still work, but so will OP's now.

Cannot remove a JPA entity using Spring Integration

When I try to remove an entity using Outbound Channel Adapter I always get removing a detached instance exception.
I know that an entity should be retrieved and deleted in the same transaction to avoid this exception, but how can I achieve it with Spring Integration?
To demonstrate the problem I modified the JPA sample:
PersonService.java
public interface PersonService {
...
void deletePerson(Person person);
}
Main.java
private static void deletePerson(final PersonService service) {
final List<Person> people = service.findPeople();
Person p1 = people.get(0);
service.deletePerson(p1);
}
spring-integration-context.xml
<int:gateway id="personService"
service-interface="org.springframework.integration.samples.jpa.service.PersonService"
default-request-timeout="5000" default-reply-timeout="5000">
<int:method name="createPerson" request-channel="createPersonRequestChannel"/>
<int:method name="findPeople" request-channel="listPeopleRequestChannel"/>
<int:method name="deletePerson" request-channel="deletePersonChannel"/>
</int:gateway>
<int:channel id="deletePersonChannel"/>
<int-jpa:outbound-channel-adapter entity-manager-factory="entityManagerFactory"
channel="deletePersonChannel" persist-mode="DELETE" >
<int-jpa:transactional transaction-manager="transactionManager" />
</int-jpa:outbound-channel-adapter>
When I call deletePerson I get the exception:
Exception in thread "main" java.lang.IllegalArgumentException:
Removing a detached instance
org.springframework.integration.samples.jpa.Person#1001
UPDATE:
Apparently I should've chosen a sample closer to my actual project, because here you can just create a new transaction programmatically and wrap both retrieve and delete function calls in it, as Artem did.
In my project I have a transformer connected to an outbound-channel-adapter. The transformer retrieves an entity and the outbound-channel-adapter removes it. How can I get the transformer and the outbound-channel-adapter to use the same transaction in this case?
To get it worked you should wrap all operations in the deletePerson to transaction, e.g.
private static void deletePerson(final PersonService service) {
new new TransactionTemplate(transactionManager)
.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
final List<Person> people = service.findPeople();
Person p1 = people.get(0);
service.deletePerson(p1);
}
});
}
In this case you should somehow provide to your method transactionManager bean too.
UPDATE:
I shown you a sample for use-case in the original question.
Now re. <transformer> -> <jpa:outbound-channel-adapter>.
In this you should understand where your message flow is started:
If it is <inbound-channel-adapter> with poller, so just make the <poller> <transactional>
If it <gateway>, who call <transformer>, so it's just enough to mark gateway's method with #Transactional
Here is one more transactional advice trick: Keep transaction within Spring Integration flow
In all cases you should get rid of <transactional> from your <jpa:outbound-channel-adapter>

GWT requestfactory: How to catch the exception i thrown in Locator at server side?

At client side:
factory.find(proxyId).fire(new Receiver<P>()
{
#Override
public void onSuccess( P response )
{
proxy = response;
...
}
#Override
public void onFailure( com.google.web.bindery.requestfactory.shared.ServerFailure error )
{
Window.alert( error.getMessage() );
}
}
at server side i use an Locator like below:
public class myLocator extends Locator<T, String>
{
#Injector LocatorHook hook;
#Override
public T find( Class<? extends T> clazz, String id )
{
T result = ...;
hook.run( result );
return result;
}
....
}
The hook.run() method may throwRunTimeException("validation exception") there, i expect to catch the
exception at client side in onFailure(), however, i did catch the exception, but the message is "Internal Server Error",
not the exception i thrown in hook.run():"validation exception".
Any ideas to let client catch the exception i throw at server side?
Updation:
As Thomas said it's weird that validating objects that come fresh from data store, but i encounter a
situation that i don't know how to use service method:
At client i get EntityProxyId object, through the factory.find( proxyId ).fire(...) i can get the entity
from datastore, but the entity may not suitable for the user to access, in this situation i need to check it at server side, but i can't find a suitable place to do the
validation, Any ideas about this?
RequestFactory doesn't expect exceptions to be thrown by locators. Exceptions should only be thrown by service methods, and will be directed to the appropriate Receiver on the client-side (the one attached to the service method that threw).
Outside service methods, the only exceptions that gets routed to the client are ReportableExceptions, that can only be thrown from a ServiceLocatorDecorator's report() methods. That means you could hook your own ServiceLocatorDecorator that catches exceptions from your locators and report()s them.
That said, validating objects that come fresh from your data store seems weird. You might want to provide a ServiceLocatorDecorator that overrides validate() (that'll validate the objects after the changes coming from the client have been applied). The errors will go back to the client in the Receiver's onConstraintViolations, and the RequestContext will be unfrozen so you can further edit your proxies and fire() again.