Disconnecting Atmosphere sockets in Grails - ajax

I'm writing a Grails application which uses Atmosphere plugin. The connection works but every time I update the page in a browser I see that my web server adds a new Daemon thread which is never released afterwards.
After the thread count reaches 200 the web server freezes.
There seems to be no documentation explaining what is exactly the right way to handle the resources (disconnect) with the Atmosphere plugin?
My client code does this:
var connectedEndpoint = null;
$(function()
{
function callback(response)
{
if (response.transport != 'polling' && response.state != 'connected' && response.state != 'closed') {
if (response.status == 200) {
eval(response.responseBody);
}
}
}
$.atmosphere.subscribe('${resource(dir: '/atmosphere/channel')}', callback, $.atmosphere.request = {transport: 'streaming'});
connectedEndpoint = $.atmosphere.response;
});
$(window).unload( function ()
{
$.atmosphere.unsubscribe();
connectedEndpoint = null;
});
I use an atmosphere handler on the server side;
package demo
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import org.atmosphere.cpr.AtmosphereHandler
import org.atmosphere.cpr.AtmosphereResource;
import org.atmosphere.cpr.AtmosphereResourceEvent;
class DemoController implements AtmosphereHandler<HttpServletRequest, HttpServletResponse> {
#Override
public void destroy() {
println "destroy"
}
#Override
public void onRequest( AtmosphereResource<HttpServletRequest, HttpServletResponse> event) throws IOException
{
event.suspend()
}
#Override
public void onStateChange( AtmosphereResourceEvent<HttpServletRequest, HttpServletResponse> event) throws IOException
{
if (event.isSuspended())
{
event.resource.response.writer.with {
def message = event.message
write "set${message.paramName}(\"${message.id}\",\"${message.value}\");"
flush()
}
}
}
}
The destroy function of the handler is never called!
The next picture shows that I have 23 threads running. When I start my application there are about 6 of them and they are added every time I press F5! If I disable atmosphere new threads are not added so this problem is related to the Atmosphere. (I am using SpringSource Tools Suite on Windows7).
If the solution is not trivial I would appreciate detailed step-by step instructions or an example.
UPDATE: After deployment in Tomcat I have the following errors each 20 seconds:
Apr 02, 2012 2:35:15 PM org.apache.catalina.startup.HostConfig deployDescriptor
INFO: Deploying configuration descriptor host-manager.xml
Apr 02, 2012 2:35:16 PM org.apache.catalina.startup.HostConfig deployDescriptor
INFO: Deploying configuration descriptor manager.xml
Apr 02, 2012 2:35:16 PM org.apache.catalina.startup.HostConfig deployDirectory
INFO: Deploying web application directory docs
Apr 02, 2012 2:35:16 PM org.apache.catalina.startup.HostConfig deployDirectory
INFO: Deploying web application directory examples
Apr 02, 2012 2:35:17 PM org.apache.catalina.startup.HostConfig deployDirectory
INFO: Deploying web application directory ROOT
Apr 02, 2012 2:35:17 PM org.apache.coyote.http11.Http11AprProtocol start
INFO: Starting Coyote HTTP/1.1 on http-8080
Apr 02, 2012 2:35:17 PM org.apache.coyote.ajp.AjpAprProtocol start
INFO: Starting Coyote AJP/1.3 on ajp-8009
Apr 02, 2012 2:35:17 PM org.apache.catalina.startup.Catalina start
INFO: Server startup in 11401 ms
2012-04-02 14:41:17,122 [http-8080-39] ERROR cpr.AsynchronousProcessor - failed
to timeout resource AtmosphereResourceImpl{, hasCode-1035775543,
action=org.atmosphere.cpr.AtmosphereServlet$Action#f2718e,
broadcaster=org.atmosphere.cpr.DefaultBroadcaster,
cometSupport=org.atmosphere.container.TomcatCometSupport#107fff7,
serializer=null,
isInScope=true,
useWriter=true,
listeners=[]}
2012-04-02 14:42:15,034 [http-8080-69] ERROR cpr.AsynchronousProcessor - failed
to timeout resource AtmosphereResourceImpl{, hasCode-58082012,
action=org.atmosphere.cpr.AtmosphereServlet$Action#ae4dd4,
broadcaster=org.atmosphere.cpr.DefaultBroadcaster,
cometSupport=org.atmosphere.container.TomcatCometSupport#107fff7,
serializer=null,
isInScope=true,
useWriter=true,
listeners=[]}
2012-04-02 14:44:41,159 [http-8080-13] ERROR cpr.AsynchronousProcessor - failed
to timeout resource AtmosphereResourceImpl{, hasCode648226529,
action=org.atmosphere.cpr.AtmosphereServlet$Action#507e61,
broadcaster=org.atmosphere.cpr.DefaultBroadcaster,
cometSupport=org.atmosphere.container.TomcatCometSupport#107fff7,
serializer=null,
isInScope=true,
useWriter=true,
listeners=[]}
....

Which web server are you using? Sound like the web server isn't detecting when the browser close the connection. You can add, in web.xml, the following timeout detector
org.atmosphere.cpr.CometSupport.maxInactiveActivity=30000 //30 seconds

I believe your issue is in your unload event. "$(window).unload". I know at least in chrome, you can't do much in the unload or beforeunload events. therefore, your browser is probably never firing the unsubscribe().
if u look at Atmospheres jquery pubsub sample, u can see the unsubscribing before connecting,
function connect() {
unsubscribe();
...
you can code a loop to check broadcasters by pushing insignificant data to validate the broadcasters periodically if they arent getting cleaned up. i need to research atmosphere more and hope for a better solution. hopefully you can clean up threads when the new connection is created from a refresh and let old ones expire with the session when the user leaves.

Related

How to obtain a client secret in a teams toolkit project?

I'm working on a tab app where I intend using an on-behalf-of flow to obtain access token from azure active directory, so as to request data from Microsoft graph endpoints, and implementing this requires a client secret.
Is there a way I can get the client secret in a teams toolkit project just like I can get an application ID?
(Update) Details of what I'm trying to do
I'm working on an app where I would be calling Microsoft graph endpoints (protected by azure ad) to get data. The challenge I'm facing currently is how to handle authentication in a Teams tab app project created using Microsoft Teams Toolkit, so as to obtain an access token to request data from the graph endpoints or create an authenticated graph client.
What I have tried:
I have tried the code below, using the teamsfx.login() function within the react component where I'm calling a protected graph endpoint. But whenever I click the button to initiate a graph call, there is always a pop-up flash.
export const GraphEmail: React.FC = () => {
const [messages, setMessages] = useState<any[]>([]);
const handleGetMyMessagesOnClick = async (event: any): Promise<void> => {
await getMessages();
};
const getMessages = async (promptConsent: boolean = false): Promise<void> => {
const teamsfx = new TeamsFx();
await teamsfx.login(["User.Read", "Mail.Read"]);
const graphClient = createMicrosoftGraphClient(teamsfx, ["User.Read", "Mail.Read"]);
await graphClient
.api("/me/messages")
.select(["receivedDateTime", "subject"])
.top(15)
.get(async (error: any, rawMessages: any, rawResponse?: any) => {
if (!error) {
setMessages(rawMessages.value);
Promise.resolve();
} else {
console.error("graph error", error);
}
});
};
return (
<Flex column gap="gap.small">
<Header>Recent messages in current user&apos;s mailbox</Header>
<Button primary
content="Get My Messages"
onClick={handleGetMyMessagesOnClick}></Button>
<List selectable>
{
messages.map((message, i) => (
<List.Item key={i} media={<EmailIcon></EmailIcon>}
header={message.receivedDateTime}
content={message.subject} index={i}>
</List.Item>
))
}
</List>
</Flex>
);
}
In order to remove the consistent flash after the first popup for the actual login, since the user is already logged-in during the first button click, I made the changes below (idea gotten from the useGraph() component code on GitHub). But then I got an "uncaught (in promise) undefined" error when the button is clicked. The console logs are displayed below too.
export const NewGraphEmail: React.FC = () => {
const [needConsent, setNeedConsent] = useState(false);
const [messages, setMessages] = useState<any[]>([]);
const handleGetMyMessagesOnClick = async (event: any): Promise<void> => {
await getMessages();
};
const getMessages = async (promptConsent: boolean = false): Promise<void> => {
const teamsfx = new TeamsFx();
const scope = ["User.Read", "Mail.Read"];
if (needConsent) {
try {
await teamsfx.login(scope);
setNeedConsent(false);
// Important: tokens are stored in sessionStorage, read more here: https://aka.ms/teamsfx-session-storage-notice
} catch (err: unknown) {
if (err instanceof ErrorWithCode && err.message?.includes("CancelledByUser")) {
const helpLink = "https://aka.ms/teamsfx-auth-code-flow";
err.message +=
'\nIf you see "AADSTS50011: The reply URL specified in the request does not match the reply URLs configured for the application" ' +
"in the popup window, you may be using unmatched version for TeamsFx SDK (version >= 0.5.0) and Teams Toolkit (version < 3.3.0) or " +
`cli (version < 0.11.0). Please refer to the help link for how to fix the issue: ${helpLink}`;
}
throw err;
}
}
const graphClient = createMicrosoftGraphClient(teamsfx, scope);
await graphClient
.api("/me/messages")
.select(["receivedDateTime", "subject"])
.top(15)
.get(async (error: any, rawMessages: any, rawResponse?: any) => {
if (!error) {
setMessages(rawMessages.value);
Promise.resolve();
} else if (error instanceof GraphError && error.code?.includes("UiRequiredError")) {
// Silently fail for user didn't consent error
setNeedConsent(true);
// getMessages();
} else {
console.log("graph error", error);
}
});
};
return (
<Flex column gap="gap.small">
<Header>Recent messages in current user&apos;s mailbox</Header>
<Button primary
content="Get My Messages"
onClick={handleGetMyMessagesOnClick}></Button>
<List selectable>
{
messages.map((message, i) => (
<List.Item key={i} media={<EmailIcon></EmailIcon>}
header={message.receivedDateTime}
content={message.subject} index={i}>
</List.Item>
))
}
</List>
</Flex>
);
}
The logs in the browser console
[Tue, 09 Aug 2022 10:22:00 GMT] : #microsoft/teamsfx : Info - Create
Microsoft Graph Client useTeamsFx.js:34
[Tue, 09 Aug 2022 10:22:00 GMT] : #microsoft/teamsfx : Info - Create
Microsoft Graph Authentication Provider with scopes: 'User.Read Mail.Read'
useTeamsFx.js:34
[Tue, 09 Aug 2022 10:22:00 GMT] : #microsoft/teamsfx : Info - Get Graph
Access token with scopes: 'User.Read Mail.Read'
useTeamsFx.js:34
[Tue, 09 Aug 2022 10:22:00 GMT] : #microsoft/teamsfx : Info - Create teams
user credential useTeamsFx.js:34
[Tue, 09 Aug 2022 10:22:00 GMT] : #microsoft/teamsfx : Verbose - Validate
authentication configuration
useTeamsFx.js:34
[Tue, 09 Aug 2022 10:22:00 GMT] : #microsoft/teamsfx : Info - Get access
token with scopes: User.Read Mail.Read
useTeamsFx.js:34
[Tue, 09 Aug 2022 10:22:00 GMT] : #microsoft/teamsfx : Verbose - Get SSO
token from memory cache
useTeamsFx.js:34
[Tue, 09 Aug 2022 10:22:00 GMT] : #microsoft/teamsfx : Verbose - Failed to
call acquireTokenSilent. Reason: no_account_error: No account object
provided to acquireTokenSilent and no active account has been set. Please
call setActiveAccount or provide an account on the request..
authorize:74 BSSO Telemetry:
{"result":"Error","error":"NoExtension","type":"ChromeSsoTelemetry","data":
{},"traces":["BrowserSSO Initialized","Creating ChromeBrowserCore
provider","Sending message for method CreateProviderAsync","Received message
for method CreateProviderAsync","Error: ChromeBrowserCore error NoExtension:
Extension is not installed."]}
DevTools failed to load source map: Could not load content for
https://login.microsoftonline.com/5d2e66da-54ba-4897-82ee-
60eeb8ce5994/oauth2/v2.0/4616d84a89b332161726.map: HTTP error: status code
404, net::ERR_HTTP_RESPONSE_CODE_FAILURE
useTeamsFx.js:34
[Tue, 09 Aug 2022 10:22:02 GMT] : #microsoft/teamsfx : Verbose - Failed to
call ssoSilent. Reason: login_required: AADSTS50058: A silent sign-in
request was sent but no user is signed in.
Trace ID: 5043daaa-b142-4083-9ad9-a798c2303b00
Correlation ID: ce16ec27-0261-423e-96f6-810344f76647
Timestamp: 2022-08-09 10:22:03Z.
useTeamsFx.js:34
[Tue, 09 Aug 2022 10:22:02 GMT] : #microsoft/teamsfx : Error - Failed to get
access token cache silently, please login first: you need login first before
get access token.
TestGraph.tsx:16
Uncaught (in promise) undefined
The uncaught error points to the end of the "handleGetMyMessagesOnClick" function above.
The other options:
The useGraph() hook: I would have loved to use the hook directly, but it seem to be suited for cases when using microsoft graph toolkit components, which won't serve my purpose during the project.
The on-behalf-of flow: I believe this would have solved the problem, following the steps in this video from the Microsoft 365 Developer channel, but the solution requires having an azure ad app client secret, which I don't know how to get in a microsoft teams toolkit project, since microsoft teams toolkit handles azure ad app registration.
A Client secret is a password to optain an access token though an API.
You need to implement an API than kan exchange an Teams SSO token, for a MS Graph API access token using a client secret (on-behalf-of). This client secret must never be exposed to the user/client, and should be secret; hence the name.
See this for a detailed explaination.
What you're wanting in this case is an "on behalf of" token from Graph, which lets you make calls to graph from your app as if it was the user ("on behalf of" the user) and it seems reasonable enough at first to do this in your client-side code. However, it turns out this isn't actually secure because it means the user's token is flying around almost in the open. As a result, it's better to create your own backend API (e.g. in an Azure Function) and make the "on behalf of" ("OBO") call from within there. Teams Toolkit actually creates some structure to help with this backend API, I think.
I'm not sure how well it covers Teams Toolkit (it's a while since I last watched it), but this video is an excellent overview: https://www.youtube.com/watch?v=kruUnaZgQaY . See here also for info: https://learn.microsoft.com/en-us/microsoftteams/platform/toolkit/visual-studio-code-tab-sso

Apache HTTPAsyncClient closes connection before response

I am sending a GET request to an API using the Apache AsyncHTTPClient version 4.1.4 (latest). I can't seem to get a response from the server.
This is my request log.
Jun 04, 2020 3:40:01 PM org.apache.http.impl.nio.client.MainClientExec generateRequest
FINE: [exchange: 2] Connection route established
Jun 04, 2020 3:40:01 PM org.apache.http.impl.nio.client.MainClientExec generateRequest
FINE: [exchange: 2] Attempt 1 to execute request
Jun 04, 2020 3:40:01 PM org.apache.http.impl.nio.client.MainClientExec generateRequest
FINE: [exchange: 2] Proxy auth state: UNCHALLENGED
Jun 04, 2020 3:40:01 PM org.apache.http.headers onRequestSubmitted
FINE: http-outgoing-1 >> GET /v1/contact?id=24 HTTP/1.1
Jun 04, 2020 3:40:01 PM org.apache.http.headers onRequestSubmitted
FINE: http-outgoing-1 >> Authorization: Bearer <token_removed>
Jun 04, 2020 3:40:01 PM org.apache.http.headers onRequestSubmitted
FINE: http-outgoing-1 >> Host: api.trial.ezyvet.com
Jun 04, 2020 3:40:01 PM org.apache.http.headers onRequestSubmitted
FINE: http-outgoing-1 >> Connection: Keep-Alive
Jun 04, 2020 3:40:01 PM org.apache.http.headers onRequestSubmitted
FINE: http-outgoing-1 >> User-Agent: Apache-HttpAsyncClient/4.1.4 (Java/11.0.6)
Jun 04, 2020 3:40:01 PM org.apache.http.impl.nio.conn.ManagedNHttpClientConnectionImpl setEvent
FINE: http-outgoing-1 192.168.1.2:52932<->52.27.52.37:443[ACTIVE][rw:][ACTIVE][rw][NEED_UNWRAP][0][0][437]: Event set [w]
Jun 04, 2020 3:40:01 PM org.apache.http.impl.nio.client.MainClientExec requestCompleted
FINE: [exchange: 2] Request completed
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 14.622 s
When I send the same request using Postman, I get a successful response.
This is my code to handle the connection.
public void connect(HttpUriRequest request, FutureCallback<HttpResponse> callback) {
SSLContextBuilder sslContextBuilder = new SSLContextBuilder();
try {
sslContextBuilder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
try (CloseableHttpAsyncClient client = HttpAsyncClients.custom()
.setSSLContext(sslContextBuilder.build())
.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
.build()) {
client.start();
client.execute(request, callback).get();
}
} catch (Exception e) {
Logger.getGlobal().severe("Couldn't execute the request using the AsyncClient.");
}
}
My debugger won't get triggered in any of the callback's methods (completed, failed, cancelled). Apparently the connection gets terminated for some reason.
Can someone explain what is happening here?
Thanks
I managed to solve this issue by changing the code to include a CountDownLatch instead of using client.execute(request, callback).get().
I passed down the latch to where the HttpResponse is read by JSON deserializer and count it down after everything completes.
This answer helped a lot.
https://stackoverflow.com/a/49359725/6663366

Hazelcast client connection disconnection events triggered even if there is still one member node remaining

I have 2 member nodes and 1 client that joins the cluster.
Member A is started on localhost 5701
JoinConfig join = config.getNetworkConfig().setPort(5701).getJoin();
join.getMulticastConfig().setEnabled(false);
join.getAwsConfig().setEnabled(false);
join.getTcpIpConfig().addMember("localhost:5701").setEnabled(true);
join.getTcpIpConfig().addMember("localhost:5702").setEnabled(true);
HazelcastInstance instance = Hazelcast.newHazelcastInstance(config);
Member B is started on localhost 5702
Config config = new Config();
JoinConfig join = config.getNetworkConfig().setPort(5702).getJoin();
join.getMulticastConfig().setEnabled(false);
join.getAwsConfig().setEnabled(false);
join.getTcpIpConfig().addMember("localhost:5701").setEnabled(true);
join.getTcpIpConfig().addMember("localhost:5702").setEnabled(true);
HazelcastInstance instance = Hazelcast.newHazelcastInstance(config);
Client joins on addresses:
config = new ClientConfig();
config.getNetworkConfig().addAddress("localhost:5701", "localhost:5702");
instance = HazelcastClient.newHazelcastClient(config);
Client adds a listener:
instance.getLifecycleService().addLifecycleListener(new LifecycleListener() {
#Override
public void stateChanged(LifecycleEvent event) {
System.out.println("LIFECYCLE State changed: " + event);
}
});
Member A is bounced.
Client receives disconnection connection events:
WARNING: hz.client_0 [dev] [3.7] Connection [/127.0.0.1:5701] lost. Reason: java.io.IOException[An existing connection was forcibly closed by the remote host]
Sep 09, 2016 12:52:19 PM com.hazelcast.core.LifecycleService
INFO: hz.client_0 [dev] [3.7] HazelcastClient 3.7 (20160817 - 1302600) is CLIENT_DISCONNECTED
LIFECYCLE State changed: LifecycleEvent [state=CLIENT_DISCONNECTED]
Sep 09, 2016 12:52:19 PM com.hazelcast.client.spi.impl.ClientMembershipListener
INFO: hz.client_0 [dev] [3.7]
Members [2] {
Member [localhost]:5701 - dc7a127d-8302-42f6-9e3e-82406162e245
Member [localhost]:5702 - cb115830-bb71-4af2-a1c1-b11f39e351c8
}
Sep 09, 2016 12:52:19 PM com.hazelcast.core.LifecycleService
INFO: hz.client_0 [dev] [3.7] HazelcastClient 3.7 (20160817 - 1302600) is CLIENT_CONNECTED
LIFECYCLE State changed: LifecycleEvent [state=CLIENT_CONNECTED]
Sep 09, 2016 12:52:24 PM com.hazelcast.client.spi.impl.ClientMembershipListener
INFO: hz.client_0 [dev] [3.7]
Members [1] {
Member [localhost]:5702 - cb115830-bb71-4af2-a1c1-b11f39e351c8
}
Now if I bounce Member A again, NO disconnect/connect events are received.
If I bounce Member B, I get the events again.
My question is why do I get these events even though at all times, at least one member is fully available? I would only expect these events only if the entire cluster is down (both members).
You are talking about CLIENT_CONNECTED and CLIENT_DISCONNECTED events (LifecycleListener), right?
These are only delivered on connecting disconnecting to the cluster (i.e. only for connections which we call as the owner for that client). You do not receive events on reconnections to non-owner members.
Client connected to 5702 and when 5701 comes back, it will not try connect to 5701 as the owner since it already has an owner connection. Hence, no event will be received at step 7, which is the expected behaviour.

Grizzly HttpServer clean shutdown got WARNING: GRIZZLY0032

I was trying to clean shutdown grizzly server. I was calling the httpServer.shutdown()
However, while I was running "mvm clean test", I got warnings like
Aug 03, 2014 10:39:00 PM org.glassfish.grizzly.http.server.NetworkListener start
INFO: Started listener bound to [localhost:8081]
Aug 03, 2014 10:39:00 PM org.glassfish.grizzly.http.server.HttpServer start
INFO: [HttpServer] Started.
Aug 03, 2014 10:39:00 PM org.glassfish.grizzly.http.server.NetworkListener shutdownNow
INFO: Stopped listener bound to [localhost:8081]
Aug 03, 2014 10:39:00 PM org.glassfish.grizzly.nio.GracefulShutdownRunner run
WARNING: GRIZZLY0030: Shutting down transport TCPNIOTransport[428da4da] in 10,000 SECONDS.
Aug 03, 2014 10:39:00 PM org.glassfish.grizzly.nio.GracefulShutdownRunner run
WARNING: GRIZZLY0032: Primary shutdown thread interrupted. Forcing transport termination.
Here is my code to shutdown the host.
protected static void shutdownGrizzlyWebServer(HttpServer grizzlyWebServer) {
if (grizzlyWebServer != null && grizzlyWebServer.isStarted()) {
GrizzlyFuture<HttpServer> future = grizzlyWebServer.shutdown(10000, TimeUnit.MILLISECONDS);
while (!future.isDone()) {
try {
Thread.sleep(2000);
} catch (InterruptedException ignore){
System.out.println(ignore);
}
}
Does anyone have any idea what goes wrong here? Thank you very much.

Apache Cayenne ROP Server "No session associated with request." on Tomcat 7

I develop a cayenne project with a java rich client and an remote obejct persistence server. If i the rich cient connects with a Cayenne-ROP-Server that is deployed on the same machine on localhost (on Jetty from maven goal like explained inside the cayenne rop tutorial) everythings fine:
ClientConnection clientConnection = new HessianConnection("http://localhost:8080/rop.server /cayenne-service",
"cayenne-user", "secret", SHARED_CAYENNE_SESSION_NAME);
DataChannel channel = new ClientChannel(clientConnection);
ObjectContext context = new CayenneContext(channel);
List<Object> someEntities = context.performQuery(allMovies);
If i change the url that i want to connect to in the first line to a non local host (Tomcat7 on ubuntu) then everything works till it comes to the 4th line:
List<Object> someEntities = context.performQuery(allMovies);
Then i get the Error "No session associated with request"
Here is the full Output of the Client:
Running de.pss.hdlist.client.dataservice.MovieDataServiceCayenneImplTest
Sep 07, 2012 10:21:37 AM org.apache.cayenne.remote.hessian.HessianConnection connect
INFO: Connecting to [cayenne-user:*******#http://comunity-server.hopto.org:8080 /rop.server-3.0.2/cayenne-service] - shared session 'global-cayenne-session'
Sep 07, 2012 10:21:40 AM org.apache.cayenne.remote.hessian.HessianConnection connect
INFO: === Connected, session: org.apache.cayenne.remote.RemoteSession#12241e[sessionId=C47DD36ACE2A043401C8D0C44D5BD8C3,n ame=global-cayenne-session] - took 3182 ms.
Sep 07, 2012 10:21:53 AM org.apache.cayenne.remote.BaseConnection sendMessage
INFO: --- Message 0: Bootstrap
Sep 07, 2012 10:21:53 AM org.apache.cayenne.remote.BaseConnection sendMessage
INFO: === Message 0: Bootstrap done - took 406 ms.
Sep 07, 2012 10:21:53 AM org.apache.cayenne.remote.BaseConnection sendMessage
INFO: --- Message 1: Query
Sep 07, 2012 10:21:53 AM org.apache.cayenne.remote.BaseConnection sendMessage
INFO: *** Message error for 1: Query - took 187 ms.
Here is the Serverside output of the Apache Tomcat log:
WARNING: org.apache.cayenne.remote.service.MissingSessionException: [v.3.0.2 Jun 19 2011 09:29:50] No session associated with request.
org.apache.cayenne.remote.service.MissingSessionException: [v.3.0.2 Jun 19 2011 09:29:50] No session associated with request.
at org.apache.cayenne.remote.service.BaseRemoteService.processMessage(BaseRemoteService.java:148)
at sun.reflect.GeneratedMethodAccessor39.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:616)
at com.caucho.hessian.server.HessianSkeleton.invoke(HessianSkeleton.java:180)
at com.caucho.hessian.server.HessianSkeleton.invoke(HessianSkeleton.java:109)
at com.caucho.hessian.server.HessianServlet.service(HessianServlet.java:396)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:224)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:581)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:987)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:579)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:307)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:679)
I use Apache Cayenne 3.0.2, Apache-Tomcat 7.0.29 and Java 7 sdk
THX in advance for every Help
PS. Maybe the local Jetty server handles things in another way as the Tomcat Server on remote unix machine.
Edit:
After the hint given by Andrus in the answer below i added an SessionListern that looks like this:
public class HttpSessionListenerLogImpl implements HttpSessionListener {
private final static Logger LOGGER = Logger.getLogger(HttpSessionListenerLogImpl.class.getName());
#Override
public void sessionCreated(HttpSessionEvent hse) {
LOGGER.log(Level.SEVERE,
"!__Session created with ID: " + hse.getSession().getId());
LOGGER.log(Level.SEVERE, "!__Session created by: " + hse.getSource());
LOGGER.log(Level.SEVERE, "!__Session Attributes: " + hse.getSession().getAttributeNames());
LOGGER.log(Level.SEVERE, "!__Session max inactivity: " + hse.getSession().getMaxInactiveInterval());
LOGGER.log(Level.SEVERE, "!__Session context: " + hse.getSession().getServletContext().getServletContextName());
}
#Override
public void sessionDestroyed(HttpSessionEvent hse) {
LOGGER.log(Level.SEVERE, "!__Session killed with ID: " + hse.getSession().getId());
LOGGER.log(Level.SEVERE, "!__Session killed by: " + hse.getSource());
LOGGER.log(Level.SEVERE, "!__Session Attributes: " + hse.getSession().getAttributeNames());
LOGGER.log(Level.SEVERE, "!__Session max inactivity: " + hse.getSession().getMaxInactiveInterval());
LOGGER.log(Level.SEVERE, "!__Session context: " + hse.getSession().getServletContext().getServletContextName());
}
So this listern gives me the following output when executing the 4 lines of code statet on top of this Question:
Sep 11, 2012 11:06:27 AM de.pss.hdlist.HttpSessionListenerLogImpl sessionCreated
SEVERE: !__Session created with ID: B07648A2A5F0005AF6DF0741D7EF2D21
Sep 11, 2012 11:06:27 AM de.pss.hdlist.HttpSessionListenerLogImpl sessionCreated
SEVERE: !__Session created by: org.apache.catalina.session.StandardSessionFacade#515f9553
Sep 11, 2012 11:06:27 AM de.pss.hdlist.HttpSessionListenerLogImpl sessionCreated
SEVERE: !__Session Attributes: java.util.Collections$2#5a44a5e1
Sep 11, 2012 11:06:27 AM de.pss.hdlist.HttpSessionListenerLogImpl sessionCreated
SEVERE: !__Session max inactivity: 216000
Sep 11, 2012 11:06:27 AM de.pss.hdlist.HttpSessionListenerLogImpl sessionCreated
SEVERE: !__Session context: Cayenne Tutorial
Sep 11, 2012 11:06:27 AM com.caucho.hessian.server.HessianSkeleton invoke
WARNING: org.apache.cayenne.remote.service.MissingSessionException: [v.3.0.2 Jun 19 2011 09:29:50] No session associated with request.
org.apache.cayenne.remote.service.MissingSessionException: [v.3.0.2 Jun 19 2011 09:29:50] No session associated with request.
at org.apache.cayenne.remote.service.BaseRemoteService.processMessage(BaseRemoteService.java:148)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:616)
at com.caucho.hessian.server.HessianSkeleton.invoke(HessianSkeleton.java:180)
at com.caucho.hessian.server.HessianSkeleton.invoke(HessianSkeleton.java:109)
at com.caucho.hessian.server.HessianServlet.service(HessianServlet.java:396)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:224)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:581)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:987)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:579)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:307)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:679)
Here you can see there is a session that gets created and there is no session that gets killed. So why does the ObjectContext from my line of code
List<Object> someEntities = context.performQuery(allMovies);
does ignore the session. Do i have to set it explicitly before doing a query? What is the standard initializing code on the client side to access an remotly deployed cayenne server. Does it differ from the one given inside the cayenne rop tutorial?
THX in advance.
Edit:
I upgraded to cayenne 3.1B1 hoping to get rid of this error, but same Situation here: "No session..." when trying to send a query.
I also setup a tomcat on localhost and configured it the same as the remote is. Same Problem here "No Session..." when trying to send a query.
So the Jetty on localhost is the only one that takes the 4 line init code from above and holds the session for every following query. So here is my Question. Does anyone on this planet ever tried to deploy a cayenne rop server on a tomcat and succeeded?
THX in advance for every little hint.
Edit:
So i did a litte bit of server side debugging on my local tomcat7.
1.Client executes line 2 of code from above:
DataChannel channel = new ClientChannel(clientConnection);
on the Serverside my session listener gets triggerd and tells me a session has been created with id: B6565298F222294F601B76333DBE4911
2.Client executes line 3 from above:
ObjectContext context = new CayenneContext(channel);
On the server side the method of class org.apache.cayenne.remote.service.HttpRemoteSession gets called:
/**
* Returns a ServerSession object that represents Cayenne-related state associated
* with the current session. If ServerSession hasn't been previously saved, returns
* null.
*/
#Override
protected ServerSession getServerSession() {
HttpSession httpSession = getSession(true);
return (ServerSession) httpSession.getAttribute(SESSION_ATTRIBUTE);
}
a new session gets created by line one of this method. Its ID is: ECC4A81D6240A1D04DA0A646200C4CE6. This new Session contains exactly one attribute: the key is "org.apache.cayenne.remote.service.HttpRemoteService.ServerSession" and the value is (who guessed it?) the session created before in step 1
What makes me wonder is that my serveltListener dont gets triggerd though a new session gets created.
3.Client executes line 4 from above
List<Object> someEntities = context.performQuery(allMovies);
at the serverside now the getServerSession() method is called again. This time also a new session gets created (why?). And this session does not contain any attribute. So the line "return (ServerSession) httpSession.getAttribute(SESSION_ATTRIBUTE);" inside the method getServerSession() returns null and exactly this triggers the exception "No Session associated with request".
So why is the cayenne serverside creating e ne session and doesnt use the old one created befor? Do i have to explicitly send the session within the query?
Edit:
I made screenshots from the netbeans http-monitor while running the four lines of code from above:
This is an issue between Cayenne ROP and newer containers:
https://issues.apache.org/jira/browse/CAY-1739
Here is a Tomcat solution - create context.xml file with the following contents, and place it in META-INF/ of your webapp:
<Context>
<Valve className="org.apache.catalina.authenticator.BasicAuthenticator"
changeSessionIdOnAuthentication="false" />
</Context>

Resources