Access Smartcloud User Profile using IBMSBT - ibm-sbt

We are using SBT as a proxy to access Smartcloud content via OAuth2.
We need to retrieve profile details for the logged in user on the server side using Java. In order to do so we call new com.ibm.sbt.services.client.smartcloud.profiles.ProfileService("smartcloudOA2").getMyProfile(). This was working fine until I realized that the returned profile object contains deprecated user profile details.
When I try to get profile details using new com.ibm.sbt.services.client.connections.profiles.ProfileService("smartcloudOA2").getMyProfile() I get following exception :
java.lang.IllegalArgumentException: Missing parameter: connections
at com.ibm.sbt.services.client.base.URLPattern.checkNoMissingParameters(URLPattern.java:67)
at com.ibm.sbt.services.client.base.URLPattern.format(URLPattern.java:58)
at com.ibm.sbt.services.client.base.URLBuilder.format(URLBuilder.java:82)
at com.ibm.sbt.services.client.connections.profiles.ProfileUrls.format(ProfileUrls.java:69)
at com.ibm.sbt.services.client.connections.profiles.ProfileService.getMyUserId(ProfileService.java:879)
at com.ibm.sbt.services.client.connections.profiles.ProfileService.getMyProfile(ProfileService.java:894)
at de.timetoact.xcc.conf.CloudServlet.doGet(CloudServlet.java:53)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:575)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:668)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1274)
at [internal classes]
at com.ibm.sbt.util.SBTFilter.doFilter(SBTFilter.java:53)
at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:194)
at [internal classes]
This is how the managed-beans.xml looks like:
...
<!-- Default Environment -->
<managed-bean>
<managed-bean-name>defaultEnvironment</managed-bean-name>
<managed-bean-class>com.ibm.sbt.jslibrary.SBTEnvironment
</managed-bean-class>
<managed-bean-scope>application</managed-bean-scope>
<managed-property>
<property-name>endpoints</property-name>
<value>smartcloudOA2</value>
</managed-property>
</managed-bean>
<managed-bean>
<managed-bean-name>smartcloudOA2</managed-bean-name>
<managed-bean-class>com.ibm.sbt.services.endpoints.SmartCloudOAuth2Endpoint
</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
<managed-property>
<property-name>url</property-name>
<value>%{smartcloud.url}</value>
</managed-property>
<managed-property>
<property-name>appName</property-name>
<value>%{smartcloud.appName}</value>
</managed-property>
<managed-property>
<property-name>clientID</property-name>
<value>%{smartcloud.clientID}</value>
</managed-property>
<managed-property>
<property-name>clientSecret</property-name>
<value>%{smartcloud.clientSecret}
</value>
</managed-property>
<managed-property>
<property-name>forceTrustSSLCertificate</property-name>
<value>true</value>
</managed-property>
<managed-property>
<property-name>credentialStore</property-name>
<value>CredStore</value>
</managed-property>
</managed-bean>
...
Is com.ibm.sbt.services.endpoints.SmartCloudOAuth2Endpoint compatible with com.ibm.sbt.services.client.connections.profiles.ProfileService ?
What is the best way to retrieve Smartcloud User Profile Information on the server side using SBT Java API?

Thanks Paul for fixing this issue - we do not get that exception anymore.
But we still are not able to get the Profile object - when we call com.ibm.sbt.services.client.connections.profiles.ProfileService("smartcloudOA2").getMyProfile() it returns null.
During debugging we saw that sbt is internally calling https://apps.na.collabserv.com/profiles/oauth/atom/profile.do?userid=[myid] in order to get my profile feed.
And when we look at response closer, we see that the profile feed is not returned back, but the html for the smartcloud login page.
When we call same url using sbt proxy via our web app smth like : https://localhost/ctx-root/service/proxy/smartcloudOA2/profiles/oauth/atom/profile.do?userid=[myid], we get the same login page instead of profile feed.
Can you please take a look at this issue again?

The issue is in getMyUserId when it passes into the namedurlpart. I've merged in a Fix.
NamedUrlPart commonPart = new NamedUrlPart("connections",ProfilesConstants.COMMON);
String peopleApiUrl = ProfileUrls.MY_USER_ID.format(this,commonPart);
It'll be in our next build, you can pull the change from github.

Related

Binding datasource to application when using springBootApplication in Liberty?

When deploying "regular" web apps to Liberty, I was used to binding the global datasource configured in Liberty's server.xml to the individual application by using a child element within the element, like this:
<application context-root="helloApp" location="..." name="helloApp" type="war">
<application-bnd>
<data-source id="db2appDs" name="jdbc/datasource" binding-name="jdbc/theDB"/>
</application-bnd>
...
</application>
<dataSource id="db2ds" jndiName="jdbc/theDB" type="javax.sql.DataSource">
...
</dataSource>
When configuring my first Spring Boot application to deploy to Liberty, I am trying to use the new <springBootApplication> element for it - but I don't seem to be able to add a binding for the datasource I want to use the same way, as this element doesn't seem to support such a child. (It seems to want only <classloader> as a child).
I've seen people suggest I use an #Resource annotation that includes both application-local JDNI name and global JNDI name for the datasorce - but that defeats the purpose, since I don't want to know what the global name is until deploy time.
Is there another way to do this, like we used to before? Or are applications deployed through <springBootApplication> expected to know the global JNDI name of the datasource(s) they want?
Application-defined datasources are not supported for <springBootApplication/>’s. While your application may certainly access a Liberty datasource using its global JNDI name, you should configure the spring.datasource.jndi-name property within your Spring Boot application as described in section 29.1.3 of the Spring Boot features reference. For your example try spring.datasource.jndi-name=jdbc/theDB.

Using Hazelcast for both Spring Session and 2 Level Cache (LC2) with Hibernate

So I want to use Hazelcast in my web application for both 2 level caching (hibernate layer) and spring session, the setup is very simple I want to be able to use NearCache configurations with a server running on the network.
I first ran into a compatibility problem recent version of Hazelcast 4.* is not yet supported in spring session, so I was happy to use the supported version: 3.12.6...
below is my hazelcast-client.xml and I have properly configured it to be used by spring.hazelcast.config=file://... when I start my application the Hazelcast instance is not created, so I decided well I should create the ClientConfig and HazelcastInstance beans myself using the code below:
#Bean()
ClientConfig clientConfig() throws IOException{
try(final InputStream stream = Files.newInputStream(Paths.get("proper-path/hazelcast-client.xml"))){
com.hazelcast.client.config.XmlClientConfigBuilder builder = new com.hazelcast.client.config.XmlClientConfigBuilder(stream);
return builder.build();
}
}
#Bean()
HazelcastInstance hazelcastInstance(final ClientConfig clientConfig){
return HazelcastClient.newHazelcastClient(clientConfig);
}
Now i have a problem, I can't add the code below so I can use it with sessions:
final MapAttributeConfig attributeConfig = new MapAttributeConfig()
.setName(HazelcastIndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE)
.setExtractor(PrincipalNameExtractor.class.getName());
hazelcastInstance.getConfig().getMapConfig(HazelcastIndexedSessionRepository.DEFAULT_SESSION_MAP_NAME)
.addMapAttributeConfig(attributeConfig)
.addMapIndexConfig(new MapIndexConfig(HazelcastIndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE, false));
hazelcast-client.xml
<?xml version="1.0" encoding="UTF-8"?>
<hazelcast-client xmlns="http://www.hazelcast.com/schema/client-config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.hazelcast.com/schema/client-config
http://www.hazelcast.com/schema/client-config/hazelcast-client-config-3.12.xsd">
<group>
<name>GroupName</name>
<password>pass</password>
</group>
<instance-name>${application.container.name}</instance-name>
<properties>
<property name="hazelcast.client.shuffle.member.list">true</property>
<property name="hazelcast.client.heartbeat.timeout">60000</property>
<property name="hazelcast.client.heartbeat.interval">5000</property>
<property name="hazelcast.client.event.thread.count">5</property>
<property name="hazelcast.client.event.queue.capacity">1000000</property>
<property name="hazelcast.client.invocation.timeout.seconds">120</property>
</properties>
<client-labels>
<label>web-app</label>
<label>${application.container.name}</label>
</client-labels>
<network>
<cluster-members>
<address>127.0.0.1</address>
</cluster-members>
<outbound-ports>
<ports>5801</ports>
</outbound-ports>
<smart-routing>true</smart-routing>
<redo-operation>true</redo-operation>
<connection-timeout>60000</connection-timeout>
<connection-attempt-period>3000</connection-attempt-period>
<connection-attempt-limit>2</connection-attempt-limit>
<socket-options>
<tcp-no-delay>false</tcp-no-delay>
<keep-alive>true</keep-alive>
<reuse-address>true</reuse-address>
<linger-seconds>3</linger-seconds>
<buffer-size>128</buffer-size>
</socket-options>
</network>
<executor-pool-size>40</executor-pool-size>
<native-memory enabled="false" allocator-type="POOLED">
<size unit="MEGABYTES" value="128"/>
<min-block-size>1</min-block-size>
<page-size>1</page-size>
<metadata-space-percentage>40.5</metadata-space-percentage>
</native-memory>
<load-balancer type="random"/>
<flake-id-generator name="default">
<prefetch-count>100</prefetch-count>
<prefetch-validity-millis>600000</prefetch-validity-millis>
</flake-id-generator>
<connection-strategy async-start="true" reconnect-mode="ASYNC">
<connection-retry enabled="true">
<initial-backoff-millis>2000</initial-backoff-millis>
<max-backoff-millis>60000</max-backoff-millis>
<multiplier>3</multiplier>
<fail-on-max-backoff>true</fail-on-max-backoff>
<jitter>0.5</jitter>
</connection-retry>
</connection-strategy>
</hazelcast-client>
You need to configure the map on the server side, which means you need to have some of the Spring classes on member's classpath. But keep in mind that you need this configuration only when HazelcastIndexedSessionRepository#findByIndexNameAndIndexValue is used.
Also in client mode, do not forget to deploy necessary classes and enable user code deployment for members. Otherwise session updates will fail:
// member
config.getUserCodeDeploymentConfig().setEnabled(true)
.setClassCacheMode(UserCodeDeploymentConfig.ClassCacheMode.ETERNAL);
// client
clientConfig.getUserCodeDeploymentConfig().setEnabled(true).addClass(Session.class)
.addClass(MapSession.class).addClass(SessionUpdateEntryProcessor.class);
But I recommend to include spring-session-hazelcast on member's cp rather than user code deployment. This will satisfy both of the needs above.
Finally, if hazelcast-client.xml exists in one of the known paths in your project (e.g. under resources/), the client will be created with this configuration. You do not need to create ClientConfig bean in that case.

Strange behavior when overriding properties for a spring-boot application deployed as a WAR in a Tomcat

I have a spring-boot application which I need to deploy as a WAR in a tomcat.
I also need to define / override some properties so that this application can work in this environment.
I was able to do so by creating a file tomcat/conf/Catalina/localhost/backend.xml with the same name as my WAR file. Here the content:
<?xml version="1.0" encoding="UTF-8"?>
<Context reloadable="true" crossContext="true" override="true" path="/back" docBase="/home/myAppUser/webapps/backend.war">
<Environment name="spring.profiles.active" value="prod" type="java.lang.String" />
<Environment name="application.attachmentBaseDirectory" value="/home/myAppUser/attachments" type="java.lang.String" />
<Environment name="application.redirect-url" value="http://myapp.mycompany.org/frontend" type="java.lang.String" />
</Context>
All environment variables but application.attachmentBaseDirectory work.
The application continue to use the one defined for my development environment on Windows: C:\tmp\attachments…
Yet, if I create a file /home/myAppUser/application.yml or /home/myAppUser/config/application.yml, the value is correctly overridden…
application:
attachmentBaseDirectory: /home/myAppUser/attachments
But if I define all the values inside this file in place of backend.xml, none of them but application.attachmentBaseDirectory work…
So here is my questions:
Why the overriding in tomcat/conf/Catalina/localhost/backend.xml isn't working for this value, but work for others?
How come the WAR is able to find the application.yml when running inside of a tomcat?
Why the application.attachmentBaseDirectory property does work from the application.yml file, but others don't?
Some more information:
Here the content on my ApplicationProperties.java.
#Component
#ConfigurationProperties("application")
public class ApplicationProperties {
/**
* The URL to which we should redirect the user once he is logged in the application.
*/
private String redirectUrl;
/**
* The base directory in which we should put the attachments.
*/
private String attachmentBaseDirectory;
}
This bean is then use in a #Controller for the redirectUrl to redirect to another web page, and in a #Service for the attachmentBaseDirectory to save files.
I finally found why the property application.attachmentBaseDirectory didn't work when set in tomcat/conf/Catalina/localhost/backend.xml:
It is because it was named application.attachmentBaseDirectory (camel case) and not application.attachment-base-directory (kebab case).
Spring-boot allow relaxed binding, but it seems that to be used through tomcat context, the kebab case way is the one to go.
Yet to solve:
How come the WAR is able to find the application.yml in the home directory when running inside tomcat?
I am suspecting that it is because I launch the tomcat from my home directory.
Why the application.attachmentBaseDirectory works from application.yml but others properties don't?

Liferay on weblogic doesn't invalidate portlet session

I use Liferay 6.2 GA4 portal on WebLogic server 10.3.6.0 and I found out one annoying problem.
I log in as UserA.
Display portlet which stores data to portlet session.
I log out.
I log in as UserB.
Display the same portlet which stores data to portlet session.
Portlet shows data of UserA instead of UserB.
I added by ext-plugin some debug log messages to com.liferay.portal.kernel.servlet.PortletSessionListenerManager and com.liferay.portal.kernel.servlet.PortletSessionTracker and found out that session (sessionId) passed to the PortletSessionTracker.add method is different than one passed to invalidate method. See log messages below:
2016-01-28 10:38:34,191 [PortletSessionTracker:40] Adding session with id=4s6HmE3LdwWuUdOilk7-ytJLqJh1LnCiTKzoeH9YVSBM2USJuxU9
2016-01-28 10:40:38,875 [PortletSessionListenerManager:187] Destroying session with id=S4qHmPDaSTLkwkmEo6gDLt4W0U-siGlU_GNa1LJelXTtQvSaRyEd
2016-01-28 10:40:38,875 [PortletSessionTracker:73] Removing session with id=S4qHmPDaSTLkwkmEo6gDLt4W0U-siGlU_GNa1LJelXTtQvSaRyEd
session.invalidate(); in com.liferay.portal.kernel.servlet.PortletSessionTracker#invalidate is not called.
There is not error in portlet because on Tomcat it works ok. And on Tomcat session.invalidate(); is called.
Weblogic.xml:
<weblogic-web-app
xmlns="http://xmlns.oracle.com/weblogic/weblogic-web-app"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd http://xmlns.oracle.com/weblogic/weblogic-web-app http://xmlns.oracle.com/weblogic/weblogic-web-app/1.2/weblogic-web-app.xsd"
>
<jsp-descriptor>
<keepgenerated>true</keepgenerated>
<page-check-seconds>60</page-check-seconds>
</jsp-descriptor>
<session-descriptor>
<debug-enabled>true</debug-enabled>
<persistent-store-type>replicated_if_clustered</persistent-store-type>
<cookie-secure>true</cookie-secure>
</session-descriptor>
<container-descriptor>
<filter-dispatched-requests-enabled>false</filter-dispatched-requests-enabled>
<prefer-application-packages>
<package-name>antlr.*</package-name>
<package-name>com.ctc.wstx.*</package-name>
<package-name>org.antlr.*</package-name>
<package-name>org.apache.commons.lang.*</package-name>
<package-name>org.mozilla.*</package-name>
<package-name>org.xmlpull.*</package-name>
</prefer-application-packages>
<optimistic-serialization>true</optimistic-serialization>
<show-archived-real-path-enabled>true</show-archived-real-path-enabled>
</container-descriptor>
<context-root>/</context-root>
<wl-dispatch-policy>ejbtp_liferay</wl-dispatch-policy>
</weblogic-web-app>
Does anybody know what could be the problem? Thanks for any idea or help.
The problem had a tricky reason. Our customer wanted to have different name for session id cookie - not the default jsessionid. I set the modified jsessionid on liferay portal war but not on another wars like theme and portlet apps. These wars therefore used the default jsessionid whereas portal used the modified one. The default one was used by add method, the modified one by invalidate method.
So solution was to modify the session id cookie also in portlet and theme wars.

Trouble with session attributes getting replicated in Tomcat 6

I have configured Tomcat 6 with in-memory session replication. I am also using IIS 7 (I know, I know) and the AJP connector via isapi_redirector. The cluster is working properly and I am able to replicate session attributes using the SessionExample in the examples war. The problem is that I am unable to do the same in my custom application. I have added the distributable tag to the web.xml file on both servers in my test cluster. However, I don't see any message in the logs mentioning the attributes getting sent to the cluster (I see them for SessionExample). The only primary differences that I can see in my app from the examples:
The examples war uses servlet 2.5. I am still required to use 2.4.
My application uses SSO and requires the user to login.
The application is a portal application.
Also, in the code of the application, I am setting a simple string in the attribute, so nothing fancy.
So, I was wondering if anyone has some tips to get this working?
Thanks
Here is the cluster section within of my server.xml:
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
channelSendOptions="6">
<Manager className="org.apache.catalina.ha.session.DeltaManager"
expireSessionsOnShutdown="false"
notifyListenersOnReplication="true"/>
<Channel className="org.apache.catalina.tribes.group.GroupChannel">
<Membership className="org.apache.catalina.tribes.membership.McastService"
address="228.0.0.104"
port="45564"
frequency="500"
dropTime="10000"/>
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
address="auto"
port="4000"
autoBind="100"
selectorTimeout="7000"
maxThreads="6"
timeout="15000"/>
<Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
<Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"
timeout="70000"/>
</Sender>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
</Channel>
<Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
filter=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;"/>
<Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
<Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
tempDir="/apache-tomcat-6.0.37/war-deploy/war-temp/"
deployDir="/apache-tomcat-6.0.37/webapps/"
watchDir="/apache-tomcat-6.0.37/war-deploy/war-listen/"
watchEnabled="true"/>
<ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
</Cluster>
Sorry. I found the issue. I was expecting to see messages in the log regarding the creation of the session attributes. I didn't realize that the examples project had a session listener that was outputting the messages to the log. I was thinking that it was simply from the log level that I had set.
Thanks to anyone who read this post.

Resources