<img height="1" width="1" style="display:none;" alt="" src="https://px.ads.linkedin.com/collect/?pid=299788&amp;fmt=gif">

Spring and HipChat Sitting in a Tree - Part 2

Software Development, Software Solutions

By Joel Brinkman

In my previous post, we set up a basic Spring Integration project to serve as an add-on to HipChat using the Atlassian Connect API. In this post we will explore using Spring Integration to swap our OAuth token for an access token using the HipChat API.
Since I know you've already read the Atlassian Connect API documentation, I'll keep to a minimum any repeating of said documentation and focus again on creating a cookbook-style approach to making something work.
The first thing we're going to do is pound some sense into our Spring Integration flow. Let's have channels for functional elements! Modify the flow to look something like this.
[xml]
&lt;alias name=&quot;conversionService&quot; alias=&quot;integrationConversionService&quot;/&gt;
&lt;int:channel id=&quot;installable&quot; /&gt;
&lt;int:channel id=&quot;accessToken&quot; /&gt;
&lt;int-http:inbound-channel-adapter id=&quot;httpChannelAdapter&quot; channel=&quot;installable&quot; supported-methods=&quot;POST&quot; path=&quot;/installable&quot; request-payload-type=&quot;java.lang.String&quot;/&gt;
&lt;int:chain input-channel=&quot;installable&quot; output-channel=&quot;accessToken&quot;&gt;
&lt;int:transformer expression=&quot;new java.lang.String(payload)&quot; /&gt;
&lt;int:json-to-object-transformer id=&quot;incomingJsonConverter&quot; type=&quot;com.isostech.swearjar.dto.HipChatInstallation&quot; /&gt;
&lt;int:service-activator expression=&quot;@tenantRepository.save(payload)&quot; /&gt;
&lt;/int:chain&gt;
&lt;int:chain input-channel=&quot;accessToken&quot; output-channel=&quot;nullChannel&quot;&gt;
&lt;int:header-enricher &gt;
&lt;int:header name=&quot;Content-Type&quot; expression=&quot;'application/x-www-form-urlencoded'&quot; /&gt;
&lt;int:header name=&quot;Authorization&quot; expression=&quot;'Basic ' + new String(T(org.apache.commons.codec.binary.Base64).encodeBase64(new java.lang.String(payload.oauthId + ':' + payload.oauthSecret).bytes))&quot; /&gt;
&lt;/int:header-enricher&gt;
&lt;int:transformer expression=&quot;@connectAuthenticationService.hipChatAddonTokenRequestBody&quot; /&gt;
&lt;int-http:outbound-gateway mapped-request-headers=&quot;Authorization,Content-Type&quot; http-method=&quot;POST&quot; url=&quot;https://api.hipchat.com/v2/oauth/token&quot; expected-response-type=&quot;java.lang.String&quot;/&gt;
&lt;int:json-to-object-transformer id=&quot;incomingJsonConverter&quot; type=&quot;com.isostech.swearjar.dto.HipChatAccessToken&quot; /&gt;
&lt;int:service-activator expression=&quot;@accessTokenRepository.save(payload)&quot; /&gt;
&lt;/int:chain&gt;
[/xml]
As you can see, the first chain listens for messages on installable, processes the message as detailed in the previous blog post and then dumps the result on the channel accessToken. The magic contained in the second chain is what we will focus on now - it fetches our access token!
As evidenced above, we have some new code and concepts to introduce. But first let's review the basic flow of the new chain.
Spring
This flow assumes that the message placed on accessToken contains an instance of Tenant in the payload. The first thing we do with this message is enhance the header with some info we'll need to make our POST to the HipChat API that will result in our access token. This is done with a very basic header-enricher. The header enricher is configured to set the content type for our request and also adds the Authorization header containing the tenant's OAuth id and secret.


By now you're probably wondering how we form the body of the request. While we could form the body within the flow, for the sake of our sanity I'll just have a simple service answer a map of the attributes we want in the request body and allow the outbound gateway take care of the details. How might such a sturdy service look? Well, check this out!


[java]
@Service
public class ConnectAuthenticationService {
public Map&lt;String, String&gt; getHipChatAddonTokenRequestBody() {
Map&lt;String, String&gt; answer = new HashMap&lt;String, String&gt;();
answer.put(&quot;grant_type&quot;, &quot;client_credentials&quot;);
answer.put(&quot;scope&quot;, &quot;send_notification send_message view_messages&quot;);
return answer;
}
}
[/java]
The very next thing that happens in our flow is the message now forms an HTTP post via outbound-gateway. Assuming all is well and good at https://api.hipchat.com/v2/oauth/token the response will contain the access token we so desire. Our JSON transformer will stuff it into a new object of the type HipChatAccessToken.
[java]
public class HipChatAccessToken {
private String access_token = null;
private Long expires_in = null;
private String group_name = null;
private String token_type = null;
private String scope = null;
private String group_id = null;
/* add dem accessors */
}
[/java]
We also need an entity to help us store this fantastic new info. It might looks like this.
[java]
@Entity
public class AccessToken extends AbstractEntity {
@NotNull
@ManyToOne()
private Tenant tenant = null;
private String accessToken = null;
private Long expiresIn = null;
private String tokenType = null;
private String scope = null;
/* add your getters and setters, yo */
}
[/java]
Don't forget a new repository!
[java]
public interface AccessTokenRepository extends Repository&lt;AccessToken, String&gt; {
AccessToken save(AccessToken entity);
}
[/java]
Now to convert from our DTO to the model, we'll introduce another Converter via a new ConverterFactory. In order to avoid dealing with some complicated injection problems with the converter, we're going to push this config into old school XML. The XML config looks like this in oldschool.xml.
[xml]
&lt;bean id=&quot;hipChatAccessTokenToAccessTokenConverterFactory&quot; class=&quot;com.isostech.swearjar.converter.HipChatAccessTokenToAccessTokenConverterFactory&quot; &gt;
&lt;/bean&gt;
&lt;bean id=&quot;hipChatInstallationToTenantConverter&quot; class=&quot;com.isostech.swearjar.converter.HipChatInstallationToTenantConverter&quot; /&gt;
&lt;bean id=&quot;conversionService&quot; class=&quot;org.springframework.context.support.ConversionServiceFactoryBean&quot;&gt;
&lt;property name=&quot;converters&quot;&gt;
&lt;list&gt;
&lt;ref bean=&quot;hipChatInstallationToTenantConverter&quot; /&gt;
&lt;ref bean=&quot;hipChatAccessTokenToAccessTokenConverterFactory&quot; /&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;/bean&gt;
[/xml]
Moving this part of the configuration into XML means we make a slight change to Application. It now looks like this.
[java]
@Configuration
@ComponentScan(basePackages=&quot;com.isostech.swearjar&quot;)
@EnableAutoConfiguration()
@PropertySource(&quot;classpath:/database.properties&quot;)
@ImportResource({&quot;classpath*:/integration/hipchat.xml&quot;, &quot;classpath*:/oldschool.xml&quot;})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
[/java]
By now you're probably anxious to see how our converter factory works. It is below.
[java]
public class HipChatAccessTokenToAccessTokenConverterFactory implements ConverterFactory&lt;HipChatAccessToken, AccessToken&gt;, ApplicationContextAware {
private ApplicationContext applicationContext;
public HipChatAccessTokenToAccessTokenConverterFactory() {
super();
}
private final class HipChatAccessTokenToAccessTokenConverter&lt;S extends HipChatAccessToken, T extends AccessToken&gt; implements Converter&lt;S, T&gt; {
private TenantRepository tenantRepository;
public HipChatAccessTokenToAccessTokenConverter(Class&lt;T&gt; entityType, TenantRepository tenantRepository) {
this.tenantRepository = tenantRepository;
}
public T convert(HipChatAccessToken dto) {
HipChatAccessTokenToAccessTokenConverterFactory factory = HipChatAccessTokenToAccessTokenConverterFactory.this;
T accessToken = (T) new AccessToken();
Tenant tenant = tenantRepository.findByGroupId(dto.getGroup_id());
accessToken.setTenant(tenant);
accessToken.setAccessToken(dto.getAccess_token());
accessToken.setExpiresIn(dto.getExpires_in());
accessToken.setScope(dto.getScope());
accessToken.setTokenType(dto.getToken_type());
return accessToken;
}
}
@Override
public &lt;T extends com.isostech.swearjar.domain.AccessToken&gt; Converter&lt;HipChatAccessToken, T&gt; getConverter(Class&lt;T&gt; targetType) {
// we are unable to autowire the repository, so we fetch it here...sad but true.
return new HipChatAccessTokenToAccessTokenConverter&lt;HipChatAccessToken, T&gt;(targetType, applicationContext.getBean(TenantRepository.class));
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
[/java]
At this point, assuming all the pieces have fallen into place, running your integration test will result in the proper retrieval of an access token for HipChat. If you're having some trouble, try downloading the source here: https://bitbucket.org/jbrinkman/swearjar

TAGS: Software Development, Software Solutions

0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Subscribe to Our Newsletter

Recent Blog Posts