Apache Camel Salesforce Integration

1. Setup SalesforceLoginConfig
2. Setup SalesforceCamelEndpointConfig
3. Setup SalesforceCamelComponent
4. Setup SalesforceCamelRouteConfig
5. Run SalesforceCamelIntegrationTest

1. Setup SalesforceLoginConfig

package com.sforce.core.camel;

import org.apache.camel.CamelContext;
import org.apache.camel.component.salesforce.SalesforceComponent;
import org.apache.camel.component.salesforce.SalesforceEndpointConfig;
import org.apache.camel.component.salesforce.SalesforceLoginConfig;
import org.apache.camel.impl.DefaultCamelContext;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Created by tmichels on 4/8/15.
 */

@Configuration
public class SalesforceCamelConfig {

    @Value("${SF_USERNAME}")
    private String username;

    @Value("${SF_PASSWORD}")
    private String password;

    @Value("${SF_TOKEN}")
    private String token;

    @Value("${SF_BASE_URL}")
    private String url;

    @Value("${SF_VERSION}")
    private String version;

    @Value("${SF_CLIENT_ID}")
    private String clientId;

    @Value("${SF_CLIENT_SECRET}")
    private String clientSecret;


    @Bean
    public SalesforceLoginConfig salesforceLoginConfig(){
        SalesforceLoginConfig salesforceLoginConfig = new SalesforceLoginConfig();
        salesforceLoginConfig.setUserName(username);
        salesforceLoginConfig.setPassword(password+token);
        salesforceLoginConfig.setLoginUrl(url);
        salesforceLoginConfig.setClientId(clientId);
        salesforceLoginConfig.setClientSecret(clientSecret);
        salesforceLoginConfig.setLazyLogin(false);
        return salesforceLoginConfig;
    }
}

2. Setup SalesforceCamelEndpointConfig

package com.sforce.core.camel;

import org.apache.camel.Endpoint;
import org.apache.camel.component.salesforce.SalesforceComponent;
import org.apache.camel.component.salesforce.SalesforceEndpoint;
import org.apache.camel.component.salesforce.SalesforceEndpointConfig;
import org.apache.camel.component.salesforce.internal.OperationName;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Created by tmichels on 4/13/15.
 */

@Configuration
public class SalesforceCamelEndpointConfig {
    
    @Bean
    public SalesforceEndpointConfig salesforceEndpointConfig(){
        SalesforceEndpointConfig salesforceEndpointConfig = new SalesforceEndpointConfig();
        salesforceEndpointConfig.setApiVersion("33.0");
        return salesforceEndpointConfig;
    }
}

3. Setup SalesforceCamelComponent

package com.sforce.core.camel;


import org.apache.camel.component.salesforce.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

/**
 * Created by tmichels on 4/13/15.
 */

@Configuration
@Import({SalesforceCamelEndpointConfig.class, SalesforceCamelConfig.class})
public class SalesforceCamelComponent {

    @Autowired
    SalesforceEndpointConfig salesforceEndpointConfig;

    @Autowired
    SalesforceLoginConfig salesforceLoginConfig;

    @Bean
    public SalesforceComponent salesforceComponent(){
        SalesforceComponent salesforceComponent = new SalesforceComponent();
        salesforceComponent.setConfig(salesforceEndpointConfig);
        salesforceComponent.setLoginConfig(salesforceLoginConfig);
        salesforceComponent.setPackages("com.sfore.core.camel");
        return salesforceComponent;
    }
}

4. Setup SalesforceCamelRouteConfig

package com.sforce.core.camel;

import com.sforce.core.config.LcGroovyPropertiesConfig;
import org.apache.camel.CamelContext;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.salesforce.SalesforceComponent;
import org.apache.camel.spring.SpringCamelContext;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.*;
import org.apache.camel.spring.javaconfig.SingleRouteCamelConfiguration;
import org.apache.camel.spring.javaconfig.Main;

/**
 * Created by tmichels on 4/10/15.
 */

@Configuration
@ComponentScan({"com.sforce.core.camel"})
public class SalesforceCamelRouteConfig extends SingleRouteCamelConfiguration implements InitializingBean {

    @Autowired
    SalesforceComponent salesforceCamelComponent;

    public static void main(String[] args) throws Exception {
        Main main = new Main();
        main.run(args);
    }


    @Override
    protected CamelContext createCamelContext() throws Exception {
        SpringCamelContext camelContext = new SpringCamelContext();
        camelContext.setApplicationContext(getApplicationContext());
        camelContext.addComponent("salesforce", salesforceCamelComponent);
        camelContext.addRoutes(route());
        camelContext.start();
        return camelContext;
    }


    @Override
    public void afterPropertiesSet() throws Exception {}

    @Bean
    @Override
    public RouteBuilder route() {
        return new RouteBuilder() {
            public void configure() {
                from("direct:getBasicInfo").to("salesforce:getBasicInfo").bean(BasicInfoBean.class);
            }
        };
    }

    public static class BasicInfoBean {
        public void someMethod(String body) {
            System.out.println(">>>>>>> Salesforce Basics Info: " + body);
        }
    }
}
package com.sforce.core.camel;

import org.apache.camel.CamelContext;
import org.apache.camel.EndpointInject;
import org.apache.camel.Produce;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.component.mock.MockEndpoint;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
 * Created by tmichels on 7/27/15.
 */

@ContextConfiguration(classes = {SalesforceCamelRouteConfig.class})
@RunWith(SpringJUnit4ClassRunner.class)
public class SalesforceCamelIntegrationTest {

    @Autowired
    CamelContext camelContext;

    @EndpointInject(uri = "direct:getBasicInfo")
    ProducerTemplate producer;

    @Test
    public void testCamelContext() throws Exception {
        String body = "Account";
        producer.sendBody(body);
    }
}

OUTPUT:

>>>>>>> Salesforce Basics Info: {"objectDescribe":{"name":"Account","label":"Account","updateable":true,"keyPrefix":"001","custom":false,"urls":{"sobject":"/services/data/v33.0/sobjects/Account","describe":"/services/data/v33.0/sobjects/Account/describe","rowTemplate":"/services/data/v33.0/sobjects/Account/{ID}","approvalLayouts":"/services/data/v33.0/sobjects/Account/describe/approvalLayouts","quickActions":"/services/data/v33.0/sobjects/Account/quickActions","listviews":"/services/data/v33.0/sobjects/Account/listviews","layouts":"/services/data/v33.0/sobjects/Account/describe/layouts","compactLayouts":"/services/data/v33.0/sobjects/Account/describe/compactLayouts"},"searchable":true,"labelPlural":"Accounts","layoutable":true,"activateable":false,"createable":true,"deprecatedAndHidden":false,"deletable":true,"customSetting":false,"feedEnabled":true,"mergeable":true,"queryable":true,"replicateable":true,"retrieveable":true,"undeletable":true,"triggerable":true},"recentItems":[{"attributes":{"type":"Account","url":"/services/data/v33.0/sobjects/Account/001W000000JhUzlIAF"},"Name":"Pope John XXIII Regional High School","Id":"001W000000JhUzlIAF"},{"attributes":{"type":"Account","url":"/services/data/v33.0/sobjects/Account/001W000000JhZFQIA3"},"Name":"A PLAZA DRIVING SCHOOL","Id":"001W000000JhZFQIA3"},{"attributes":{"type":"Account","url":"/services/data/v33.0/sobjects/Account/001W000000JgxxXIAR"},"Name":"Advanced Reproductive Care, Inc. (ARC)","Id":"001W000000JgxxXIAR"},{"attributes":{"type":"Account","url":"/services/data/v33.0/sobjects/Account/001W000000JrwqvIAB"},"Name":"name","Id":"001W000000JrwqvIAB"},{"attributes":{"type":"Account","url":"/services/data/v33.0/sobjects/Account/001W000000JhXSnIAN"},"Name":"Stella Niagara Education Park","Id":"001W000000JhXSnIAN"},{"attributes":{"type":"Account","url":"/services/data/v33.0/sobjects/Account/001W000000Jr1WOIAZ"},"Name":"A J DIANA SONS INC","Id":"001W000000Jr1WOIAZ"},{"attributes":{"type":"Account","url":"/services/data/v33.0/sobjects/Account/001W000000Jr1TIIAZ"},"Name":"A J DIANA SONS COMPANY","Id":"001W000000Jr1TIIAZ"},{"attributes":{"type":"Account","url":"/services/data/v33.0/sobjects/Account/001W000000Jr1WNIAZ"},"Name":"A J DIANA SONS INC","Id":"001W000000Jr1WNIAZ"},{"attributes":{"type":"Account","url":"/services/data/v33.0/sobjects/Account/001W000000JqzmSIAR"},"Name":"A J DIANA SONS INC","Id":"001W000000JqzmSIAR"},{"attributes":{"type":"Account","url":"/services/data/v33.0/sobjects/Account/001W000000Jq8TeIAJ"},"Name":"A J DIANA SONS COMPANY","Id":"001W000000Jq8TeIAJ"},{"attributes":{"type":"Account","url":"/services/data/v33.0/sobjects/Account/001W000000JhZLTIA3"},"Name":"name","Id":"001W000000JhZLTIA3"},{"attributes":{"type":"Account","url":"/services/data/v33.0/sobjects/Account/001W000000Jq8LVIAZ"},"Name":"A PLAZA DRIVING SCHOOL","Id":"001W000000Jq8LVIAZ"},{"attributes":{"type":"Account","url":"/services/data/v33.0/sobjects/Account/001W000000JhZBTIA3"},"Name":"A J DIANA SONS INC","Id":"001W000000JhZBTIA3"},{"attributes":{"type":"Account","url":"/services/data/v33.0/sobjects/Account/001W000000JgxwjIAB"},"Name":"[First]Name [Last]Name","Id":"001W000000JgxwjIAB"},{"attributes":{"type":"Account","url":"/services/data/v33.0/sobjects/Account/001W000000JhUlVIAV"},"Name":"Central Texas Christian School","Id":"001W000000JhUlVIAV"},{"attributes":{"type":"Account","url":"/services/data/v33.0/sobjects/Account/001W000000JhKbtIAF"},"Name":"Sylvan Learning Center - 112","Id":"001W000000JhKbtIAF"}]}

Jax-rs Basic Authentication using HeaderParam

@Path("/v1/docs")
@Consumes({ MediaType.APPLICATION_JSON })
@Named
@Api(value = "/v1/docs", description = "Docs Service" )
public interface DocumentService {

    @POST
    @Path("/{caseId}/{emailMessageid}")
    @PermitAll
    @ApiOperation(value = "Docs Service",
            notes = "Create Salesforce Account, Contact"
    )
    @ApiResponses(value = {
            @ApiResponse(code = 500, message = "Unexpected failure")
    })
    void uploadAndDeleteDocumentFromSalesforceAndUpdateCase(@PathParam("caseId") String caseId, 
                                                            @PathParam("emailMessageid") String emailMessageid,  
                                                            @HeaderParam("authorization") String authentication);
}
@Named
public class DocumentServiceImpl implements DocumentService {

    private static final Logger logger = org.slf4j.LoggerFactory.getLogger(DocumentServiceImpl.class);

    @Value("${SF_DOCS_USERNAME}")
    private String sfDocsUsername;

    @Value("${SF_DOCS_PASSWORD}")
    private String sfDocsPassword;

    @Override
    public synchronized void uploadAndDeleteDocumentFromSalesforceAndUpdateCase(String caseId, String emailMessageId, String authentication) {
        if(isUserAuthenticated(authentication)){
          
        } else {
            logger.error("caseId {} emailId {} authentication failed {}", caseId, emailMessageId, authentication);
        }
    }

    public boolean isUserAuthenticated(String authString){
        if (authString!=null){
            String[] authParts = authString.split("\\s+");
            String authInfo = authParts[1];
            byte[] bytes  =  DatatypeConverter.parseBase64Binary(authInfo);
            String decodedAuth = new String(bytes);
            String[] userNameAndPassword = decodedAuth.split(":");
            if (userNameAndPassword[0].equals(sfDocsUsername) && userNameAndPassword[1].equals(sfDocsPassword)){
                return true;
            } else
                logger.info("isUserAuthenticated did not match decodedAuth {} username {}", decodedAuth, sfDocsUsername+":"+sfDocsPassword);
        }
        return false;
    }
}

Setup Spring EnableCaching for Memcached


1. Setup CacheConfiguration
2. Extend AbstractCacheManager
3. Implement Cache
4. Implement CachingConfigurer

1. Setup CacheConfiguration

package com.example.cache;

import java.io.IOException;
import java.net.URISyntaxException;

import net.spy.memcached.AddrUtil;
import net.spy.memcached.ConnectionFactory;
import net.spy.memcached.ConnectionFactoryBuilder;
import net.spy.memcached.MemcachedClient;
import net.spy.memcached.auth.AuthDescriptor;
import net.spy.memcached.auth.PlainCallbackHandler;

import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class CacheConfiguration {

    @Bean
    public MemcachedClient memcachedCloudConfiguration() {
        try {
            AuthDescriptor ad = new AuthDescriptor(new String[] { "PLAIN" },
                    new PlainCallbackHandler(System.getenv("MEMCACHEDCLOUD_USERNAME"), System.getenv("MEMCACHEDCLOUD_PASSWORD")));

            MemcachedClient mc = new MemcachedClient(
                    new ConnectionFactoryBuilder()
                            .setTranscoder(new CustomSerializingTranscoder())
                            .setProtocol(ConnectionFactoryBuilder.Protocol.BINARY)
                            .setAuthDescriptor(ad).build(),
                    AddrUtil.getAddresses(System.getenv("MEMCACHEDCLOUD_SERVERS")));

            return mc;
        } catch (IOException ex) {
            // the Memcached client could not be initialized.
        }
        return null;
    }
}

2. Extend AbstractCacheManager

package com.example.cache;

import org.springframework.cache.Cache;
import org.springframework.cache.support.AbstractCacheManager;
import org.springframework.util.Assert;

import java.util.Collection;

/**
 * Created by tmichels on 3/19/15.
 */
public class MemCacheManager extends AbstractCacheManager {
    private final Collection<MemCache> internalCaches;

    public MemCacheManager(final Collection<MemCache> internalCaches) {
        this.internalCaches = internalCaches;
    }

    @Override
    protected Collection<? extends Cache> loadCaches() {
        Assert.notNull(internalCaches, "A collection caches is required and cannot be empty");
        return internalCaches;
    }
}

3. Implement Cache

package com.example.cache;

import net.spy.memcached.AddrUtil;
import net.spy.memcached.MemcachedClient;
import net.spy.memcached.transcoders.SerializingTranscoder;
import org.apache.log4j.Logger;
import org.junit.Assert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.support.SimpleValueWrapper;

import java.io.IOException;
import java.net.URISyntaxException;

/**
 * Created by tmichels on 3/19/15.
 */
public class MemCache implements Cache {

    @Autowired
    MemcachedClient cache;

    private final String name = "";
    private static final Logger LOGGER = Logger.getLogger(MemCache.class);

    @Override
    public String getName() {
        return name;
    }

    @Override
    public Object getNativeCache() {
        return cache;
    }

    @Override
    public ValueWrapper get(final Object key) {
        Object value = null;
        try {
            value = cache.get(key.toString());
        } catch (final Exception e) {
            LOGGER.warn(e);
        }
        if (value == null) {
            return null;
        }
        return new SimpleValueWrapper(value);
    }

    @Override
    public void put(final Object key, final Object value) {
        cache.set(key.toString(), 7 * 24 * 3600, value);
        Assert.assertNotNull(get(key)); //This fails on the viewCache
    }

    @Override
    public void evict(final Object key) {
        this.cache.delete(key.toString());
    }

    @Override
    public void clear() {
        cache.flush();
    }
 }

4. Implement CachingConfigurer

package com.example.cache;

import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurer;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCache;
import org.springframework.cache.interceptor.DefaultKeyGenerator;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableCaching
public class SimpleCacheConfiguration implements CachingConfigurer {

    @Override
    @Bean
    public CacheManager cacheManager() {
        CacheManager cacheManager;
        try {
            cacheManager = new MemCacheManager(internalCaches());
            return cacheManager;
        } catch (final URISyntaxException e) {
            throw new RuntimeException(e);
        }
    }

    @Bean
    public Collection<MemCache> internalCaches() throws URISyntaxException {
        final Collection<MemCache> caches = new ArrayList<MemCache>();
        caches.add(new MemCache());
        return caches;
    }

    @Override
    public KeyGenerator keyGenerator() {
        return new DefaultKeyGenerator();
    }

}

Metrics Dashboard using STOMP WebSocket

http://cloudsole-metrics.herokuapp.com
https://github.com/thysmichels/cloudsole-metrics

1. Basic WebAppInitializer
2. WebConfiguration with EnableScheduling
3. WebSocketConfiguration with EnableWebSocketMessageBroker
4. Random Number Generator with ApplicationListener
5. Sock.js Javascript

1. Basic WebAppInitializer

package  com.thysmichels.websockets.configuration;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.context.support.GenericWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

public class WebAppInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(final ServletContext context) throws ServletException {

        final AnnotationConfigWebApplicationContext root = new AnnotationConfigWebApplicationContext();

        root.scan("com.thysmichels.websockets");

        context.addListener(new ContextLoaderListener(root));

        final ServletRegistration.Dynamic appServlet = context.addServlet("appServlet",new DispatcherServlet(new GenericWebApplicationContext()));
        appServlet.setAsyncSupported(true);
        appServlet.setLoadOnStartup(1);
        appServlet.addMapping("/*");
    }
}

2. WebConfiguration with EnableScheduling

package  com.thysmichels.websockets.configuration;

import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
@EnableWebMvc
@EnableScheduling
public class WebConfiguration extends WebMvcConfigurerAdapter {

    @Override
    public void configureDefaultServletHandling(
        final DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}

3. WebSocketConfiguration with EnableWebSocketMessageBroker

package  com.thysmichels.websockets.configuration;

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfiguration implements WebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
    }

    @Override
    public void registerStompEndpoints(final StompEndpointRegistry registry) {
        registry.addEndpoint("/metrics").withSockJS();
    }

    @Override
    public void configureClientInboundChannel(final ChannelRegistration registration) {}

    @Override
    public void configureClientOutboundChannel(final ChannelRegistration registration) { }

}

4. Random Number Generator with ApplicationListener

package  com.thysmichels.websockets.utils;

import java.util.Random;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.messaging.core.MessageSendingOperations;
import org.springframework.messaging.simp.broker.BrokerAvailabilityEvent;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class RandomDataGenerator implements ApplicationListener<BrokerAvailabilityEvent> {

    private final MessageSendingOperations<String> messagingTemplate;

    @Autowired
    public RandomDataGenerator(final MessageSendingOperations<String> messagingTemplate) {
        this.messagingTemplate = messagingTemplate;
    }

    @Override
    public void onApplicationEvent(final BrokerAvailabilityEvent event) {
    }

    @Scheduled(fixedDelay = 1000)
    public void sendDataUpdates() {
        this.messagingTemplate.convertAndSend("/data", new Random().nextInt(100));
    }
}

5. Sock.js Javascript

/**
 * Created by tmichels on 8/19/14.
 */

//var stompClient = null;
var updateOpts = {'minVal':'0','maxVal':'100','newVal':'1'};

var randomData;
var socket = new SockJS('/metrics');
var client = Stomp.over(socket);

client.connect('admin', 'password', function(frame) {

    client.subscribe("/data", function(message) {
        var point = [ (new Date()).getTime(), parseInt(message.body) ];
        gaugeUpdate('cf-gauge-1', {'minVal':'0','maxVal':'100','newVal':parseInt(message.body)})
        $('#spark-1').each(function(){

            customSparkOptions = {};
            customSparkOptions.minSpotColor = true;
            var sparkOptions = cf_defaultSparkOpts;
            var sparkOptions = $.extend({}, cf_defaultSparkOpts, customSparkOptions);

            data.push(parseInt(message.body));
            createSparkline($(this), data, sparkOptions);
        });

        $('#metric-1 .metric').html(message.body);
        $('#metric-1 .large').html(message.body);
        $('#metric-2 .metric').html(message.body);
        $('#metric-2 .large').html(message.body);
        var element = $(this).data('update');
        cf_rSVPs[$('#svp-1').attr('id')].chart.update(parseInt(message.body));
        $('#svp-1 .chart').data('percent', parseInt(message.body));
        $('#svp-1 .metric').html(message.body);
       // $('#cf-svmc-sparkline .metric').html(message.body);

        $('#cf-rag-1').each(function(){
            // Dummy data for RAG
            ragData = [60,30,parseInt(message.body)];
            ragLabels = ['Success','Bounce','Abandoned'];
            ragOpts = {postfix:'%'}

            cf_rRags[$(this).prop('id')] = new RagChart($(this).prop('id'), ragData, ragLabels, ragOpts);
        });

        $('#cf-pie-1').each(function(){

            var pdata = [
                {
                    value : parseInt(message.body),
                    color : pieSegColors[3],
                    label: 'Success'
                },
                {
                    value : parseInt(message.body)+50,
                    color : pieSegColors[2],
                    label: 'Bounce'
                },
                {
                    value: parseInt(message.body)+100,
                    color: pieSegColors[1],
                    label: 'Abandoned'
                }
            ]

            var $container = $(this);
            var pId = $container.prop('id');

            // Store chart information
            cf_rPs[pId] = {};
            cf_rPs[pId].data = pdata;


             // Set options per chart
             customOptions = {};
             customOptions.animation = false;
             cf_rPs[pId].options = customOptions;

            // Create chart
            createPieChart($container);
        });

        $('#cf-funnel-1').each(function(){
            funData = [parseInt(message.body)+3000,parseInt(message.body)+1500,parseInt(message.body)+500,parseInt(message.body)+250,parseInt(message.body)];
            funLabels = ['Visits','Cart','Checkout','Purchase','Refund'];
            funOptions = {barOpacity:true, layout:'left'};

            cf_rFunnels[$(this).prop('id')] = new FunnelChart($(this).prop('id'), funData, funLabels, funOptions);
        });

    });
});


LendingClub Java Client

https://github.com/thysmichels/lendingclub-java-client

The minimum requirements to get started using LendingClub API:
1. Setup wsimport maven plugin
2. Run mvn clean install to generate LendingClub API Java classes from wsdl
3. Create basic LendingClub Main Class
4. Output

1. Setup wsimport maven plugin

         <plugin>
            <groupId>org.jvnet.jax-ws-commons</groupId>
            <artifactId>jaxws-maven-plugin</artifactId>
            <version>2.3</version>
            <executions>
                <execution>
                    <goals>
                        <goal>wsimport</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <wsdlUrls><wsdlUrl>https://www.lendingclub.com/ws/1.4?wsdl</wsdlUrl></wsdlUrls>
                <verbose>true</verbose>
            </configuration>
        </plugin>

2. Run mvn clean install to generate LendingClub API Java classes from wsdl

mvn clean install
...

[INFO] --- jaxws-maven-plugin:2.3:wsimport (default) @ lendingclub-java-client ---
[INFO] Processing: https://www.lendingclub.com/ws/1.4?wsdl
[INFO] jaxws:wsimport args: [-keep, -s, /Users/tmichels/git/lendingclub-java-client/target/generated-sources/wsimport, -d, /Users/tmichels/git/lendingclub-java-client/target/classes, -verbose, -encoding, UTF-8, -Xnocompile, "https://www.lendingclub.com/ws/1.4?wsdl"]
parsing WSDL...



Generating code...

com/lendingclub/ws/BadArgumentException.java
com/lendingclub/ws/BadArgumentExceptionInfo.java
com/lendingclub/ws/BrowseLoansResult.java
com/lendingclub/ws/CreatePortfolioResult.java
com/lendingclub/ws/CreditInfo.java
com/lendingclub/ws/ExcessiveRequestsException.java
com/lendingclub/ws/ExcessiveRequestsExceptionInfo.java
com/lendingclub/ws/GetPortfoliosResult.java
com/lendingclub/ws/HomeOwnership.java
com/lendingclub/ws/IncomeVerification.java
com/lendingclub/ws/InvalidCredentialsException.java
com/lendingclub/ws/InvalidCredentialsExceptionInfo.java
com/lendingclub/ws/LendingClubV14.java
com/lendingclub/ws/LendingClubV14_Service.java
com/lendingclub/ws/LoanBrowseLoans.java
com/lendingclub/ws/LoanBrowseLoansResponse.java
com/lendingclub/ws/LoanGrade.java
com/lendingclub/ws/LoanListing.java
com/lendingclub/ws/LoanPurpose.java
com/lendingclub/ws/LoanSubGrade.java
com/lendingclub/ws/MissingCredentialsException.java
com/lendingclub/ws/MissingCredentialsExceptionInfo.java
com/lendingclub/ws/ObjectFactory.java
com/lendingclub/ws/Order.java
com/lendingclub/ws/OrderConfirmation.java
com/lendingclub/ws/OrderCreatePortfolio.java
com/lendingclub/ws/OrderCreatePortfolioResponse.java
com/lendingclub/ws/OrderExecutionStatus.java
com/lendingclub/ws/OrderGetPortfolios.java
com/lendingclub/ws/OrderGetPortfoliosResponse.java
com/lendingclub/ws/OrderInstruct.java
com/lendingclub/ws/OrderInstructConfirmation.java
com/lendingclub/ws/OrderSubmitOrders.java
com/lendingclub/ws/OrderSubmitOrdersResponse.java
com/lendingclub/ws/Portfolio.java
com/lendingclub/ws/PortfolioResult.java
com/lendingclub/ws/ReviewStatus.java
com/lendingclub/ws/SubmitOrderResult.java
com/lendingclub/ws/SystemGetVersion.java
com/lendingclub/ws/SystemGetVersionResponse.java
com/lendingclub/ws/UnauthorizedWebserviceUserException.java
com/lendingclub/ws/UnauthorizedWebserviceUserExceptionInfo.java
com/lendingclub/ws/VersionInfo.java
com/lendingclub/ws/VersionStatus.java
com/lendingclub/ws/package-info.java

3. Create basic LendingClub Main Class

package com.lendingclub.main;

import com.lendingclub.exception.WebRequestException;
import com.lendingclub.ws.*;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.handler.MessageContext;

/**
 * Created by tmichels on 8/21/14.
 */
public class Main {

   private static final String LENDINGCLUB_API_KEY = "PASTE_YOUR_API_KEY_HERE";

    public static void main(String[] args) throws WebRequestException, UnauthorizedWebserviceUserException, ExcessiveRequestsException, InvalidCredentialsException, MissingCredentialsException {
        final String endpointUrl = "https://api.lendingclub.com:443/ws/1.4";
        Map<String, List<String>> headers = new HashMap<String,List<String>>();
        headers.put("Authorization", Collections.singletonList(LENDINGCLUB_API_KEY));
        LendingClubV14_Service lcSvc = new LendingClubV14_Service();
        LendingClubV14 lcWs = lcSvc.getLendingClubV14Port();
        Map<String, Object> requestContext = ((BindingProvider) lcWs).getRequestContext();
        requestContext.put(MessageContext.HTTP_REQUEST_HEADERS, headers);
        requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpointUrl);

        BrowseLoansResult browseLoansResult = lcWs.loanBrowseLoans(true);
        for (LoanListing ll : browseLoansResult.getLoans()){
            System.out.println("Loan: " + ll.getTitle() + " " + ll.getGrade());
        }
    }
}

4. Output

Loan: Debt consolidation B
Loan: Debt consolidation D
Loan: Credit card refinancing A
Loan: Credit card refinancing D

Using LendingClub Java Client library
1. LendingClub API Connection Config
2. LendingClub Client Service
3. LendingClub Client Main Class
4. LendingClub Client Config Test
5. LendingClub Client Tests

1. LendingClub API Connection Config

package com.lendingclub.config;

import com.lendingclub.ws.LendingClubV14;
import com.lendingclub.ws.LendingClubV14_Service;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

import javax.xml.ws.BindingProvider;
import javax.xml.ws.handler.MessageContext;
import java.util.*;

/**
 * Created by tmichels on 8/21/14.
 */

@Configuration
@PropertySource("classpath:/system.properties")
public class ConnectionConfig {

    @Value("${lendingclub_api_key}")
    private String lendingclubKey;

    @Value("${lendingclub_api_url:https://api.lendingclub.com:443/ws/1.4}")
    private String lendingclubEndpoint;

    @Bean
    public LendingClubV14 lcConnection(){

        Map<String, List<String>> headers = new HashMap<String,List<String>>();
        headers.put("Authorization", Arrays.asList(lendingclubKey));

        LendingClubV14_Service lcSvc = new LendingClubV14_Service();
        LendingClubV14 lcWs = lcSvc.getLendingClubV14Port();
        Map<String, Object> requestContext = ((BindingProvider) lcWs).getRequestContext();

        // 1 minute for connection
        ((BindingProvider) lcWs).getRequestContext().put("com.sun.xml.ws.connect.timeout", 1 * 60 * 1000);
        // 1 minute for request
        ((BindingProvider) lcWs).getRequestContext().put("com.sun.xml.ws.request.timeout", 1 * 60 * 1000);

        requestContext.put(MessageContext.HTTP_REQUEST_HEADERS, headers);
        requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, lendingclubEndpoint);
        return lcWs;
    }
}

2. LendingClub Client Service

@Service
public class LendingClubClient {

    @Autowired
    private LendingClubV14 lcConnection;

    public BrowseLoansResult getLoans(boolean recentlyListed) throws Exception {
        return lcConnection.loanBrowseLoans(!recentlyListed);
    }

    public VersionInfo getSystemVersion() throws ExcessiveRequestsException {
        return lcConnection.systemGetVersion();
    }

    public void submitOrders(List<OrderInstruct> orderInstructList) throws Exception {
        lcConnection.orderSubmitOrders(orderInstructList);
    }

    public GetPortfoliosResult getPortfolios(Long portfolioId) throws Exception {
        return lcConnection.orderGetPortfolios(portfolioId);
    }

    public CreatePortfolioResult orderCreatePortfolio(Portfolio portfolio) throws Exception {
        return lcConnection.orderCreatePortfolio(portfolio);
    }
}

3. LendingClub Client Main Class

public class MainSpring {

    public static void main(String[] args) throws Exception {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.scan("com.lendingclub");
        applicationContext.refresh();

        LendingClubClient loanService = applicationContext.getBean(LendingClubClient.class);

        BrowseLoansResult browseLoansResult = loanService.getLoans(true);
        for (LoanListing loanListing : browseLoansResult.getLoans()){
            System.out.println("Loans: " + loanListing.getTitle() + " " + loanListing.getGrade());
        }
    }
}

4. Lending Club Client Config Test

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {WSConnectionConfig.class, ClientConfig.class} , loader = AnnotationConfigContextLoader.class)
public class ConnectionConfigTest {

    @Autowired
    LendingClubV14 lcConnection;

    @Test
    public void testlcWSConnection() throws ExcessiveRequestsException {
        Assert.assertEquals(lcConnection.systemGetVersion().getNumber(), "1.4");
        Assert.assertEquals(lcConnection.systemGetVersion().getStatus().value(), "ACTIVE");
    }
}

5. Lending Club Client Tests

package com.lendingclub.client;

import com.lendingclub.ClientConfig;
import com.lendingclub.config.WSConnectionConfig;
import com.lendingclub.ws.Order;
import com.lendingclub.ws.OrderInstruct;
import com.lendingclub.ws.Portfolio;
import com.lendingclub.ws.SubmitOrderResult;
import junit.framework.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
import org.springframework.web.bind.annotation.ExceptionHandler;

import java.util.Arrays;

/**
 * Created by tmichels on 8/22/14.
 */

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {WSConnectionConfig.class, ClientConfig.class, LendingClubClient.class} , loader = AnnotationConfigContextLoader.class)
public class LendingClubClientTest {

    @Autowired
    LendingClubClient lcClient;

    @Test
    public void testGetLoans() throws Exception {
        Assert.assertNotNull(lcClient.getLoans(true));
    }

    @Test
    public void testGetPortfolios() throws Exception {
        Assert.assertNotNull(lcClient.getPortfolios(new Long(6817950)));
    }

    @Test
    public void testOrderCreatePortfolio() throws Exception {
        Portfolio portfolio = new Portfolio();
        portfolio.setAid(new Long(6817950));
        portfolio.setPortfolioDescription("Dummy portfolio description");
        portfolio.setPortfolioName("Dummy portfilio");
        Assert.assertNotNull(lcClient.orderCreatePortfolio(portfolio));
    }

    @Test
    public void testSubmitOrders() throws Exception {
        OrderInstruct orderInstruct = new OrderInstruct();
        orderInstruct.setAid(new Long(6817950));
        lcClient.submitOrders(Arrays.asList(orderInstruct));
    }
}

Spring MVC AngularJS Address Book

Try it: http://cloudsole-angular.herokuapp.com
Clone it: https://github.com/thysmichels/cloudsole-angular

1. Address Book Model
2. Address Book Service
3. Address Book Service Implementation
4. Address Book Controller
5. Address Book Angular Controller
6. Address Book HTML

1. Address Book Model

package com.cloudsole.angular.model;

/**
 * Created by tmichels on 8/3/14.
 */
public class AddressBook {

    private long id;
    private String firstName;
    private String lastName;
    private String phone;
    private String email;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

2. Address Book Service

package com.cloudsole.angular.service;

import com.cloudsole.angular.model.AddressBook;

import java.util.List;

/**
 * Created by tmichels on 8/3/14.
 */
public interface AddressBookService {
     List<AddressBook> viewAllAddressBook();
     void createAddressBook(AddressBook addressBook);
     void updateAddressBook(int pos, AddressBook updateAddressBook);
     void deleteAddressBook(int id);
     void deleteAllAddressBook();
     AddressBook findAddressBook(int id);
}

3. Address Book Service Implementation

package com.cloudsole.angular.service;

import com.cloudsole.angular.model.AddressBook;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by tmichels on 8/3/14.
 */
@Service
public class AddressBookServiceImpl implements AddressBookService {

    List<AddressBook> addressBooks = new ArrayList<AddressBook>();
    private static Long id = 0L;

    @Override
    public List<AddressBook> viewAllAddressBook() {
        return addressBooks;
    }

    @Override
    public void createAddressBook(AddressBook addressBook) {
        addressBook.setId(id);
        addressBooks.add(addressBook);
        ++id;
    }

    @Override
    public void updateAddressBook(int pos, AddressBook updateAddressBook) {
        addressBooks.set(pos, updateAddressBook);
    }

    @Override
    public void deleteAddressBook(int id) {
        addressBooks.remove(id);
    }

    @Override
    public void deleteAllAddressBook() {
        addressBooks.clear();
        id = 0L;
    }

    @Override
    public AddressBook findAddressBook(int id) {
        return addressBooks.get(id);
    }
}

4. Address Book Controller

package com.cloudsole.angular.controller;

import com.cloudsole.angular.model.AddressBook;
import com.cloudsole.angular.service.AddressBookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * Created by tmichels on 8/3/14.
 */

@Controller
@RequestMapping("/address")
public class AddressBookController {

    @Autowired
    AddressBookService addressBookService;

    @RequestMapping(value = "/all.json", method = RequestMethod.GET)
    public @ResponseBody List<AddressBook> viewAllAddressBook(){
        return addressBookService.viewAllAddressBook();
    }

    @RequestMapping(value = "/add", method = RequestMethod.POST)
    public @ResponseBody void addAddressBookEntry(@RequestBody AddressBook addressBook){
        addressBookService.createAddressBook(addressBook);
    }

    @RequestMapping(value = "/delete/{id}", method = RequestMethod.DELETE)
    public @ResponseBody void deleteAddressBookEntry(@PathVariable("id") String id){
        addressBookService.deleteAddressBook(Integer.valueOf(id));
    }

    @RequestMapping(value = "/update/{pos}", method = RequestMethod.PUT)
    public @ResponseBody void updateAddressBook(@RequestBody AddressBook addressBook, @PathVariable("pos") String pos){
        addressBookService.updateAddressBook(Integer.valueOf(pos), addressBook);
    }

    @RequestMapping(value="/delete/all", method = RequestMethod.DELETE)
    public @ResponseBody void deleteAllAddressBook(){
        addressBookService.deleteAllAddressBook();
    }

    @RequestMapping("/layout")
    public String getTodoPartialPage() {
        return "addressbook/layout";
    }
}

5. Address Book Angular Controller

/**
 * Created by tmichels on 8/3/14.
 */


var AddressBookController = function($scope, $http){

    $scope.editMode = false;
    $scope.position = '';

    $scope.viewAllAddressBook = function(){
        $http.get('address/all.json').success(function(response){
            $scope.addressBooks = response;
        })
    }

    $scope.resetAddressBookField = function(){
        $scope.ab.firstName='';
        $scope.ab.lastName='';
        $scope.ab.phone = '';
        $scope.ab.email = '';
        $scope.editMode = false;
    }

    $scope.addAddressBook = function(ab) {
        $http.post('address/add', ab).success(function(response){
            $scope.viewAllAddressBook();
            $scope.ab.firstName='';
            $scope.ab.lastName='';
            $scope.ab.phone = '';
            $scope.ab.email = '';
        }).error(function(response){
            console.log(response);
        })
    }

    $scope.updateAddressBook = function(ab) {
        $http.put('address/update/'+$scope.position, ab).success(function(response){
            $scope.ab.firstName='';
            $scope.ab.lastName='';
            $scope.ab.phone = '';
            $scope.ab.email = '';
            $scope.viewAllAddressBook();
            $scope.editMode = false;
        }).error(function(response){
            console.log(response);
        })
    }

    $scope.deleteAddressBook = function(id) {
        $http.delete('address/delete/' + id).success(function(response){
            $scope.viewAllAddressBook();
        }).error(function(response){
            console.log(response);
        })
    }

    $scope.deleteAllAddressBook = function(){
        $http.delete('address/delete/all').success(function(response){
            $scope.viewAllAddressBook();
        })
    }

    $scope.editAddressBook = function(pos, addressBook){
        $scope.position = pos;
        $scope.ab = addressBook;
        $scope.editMode = true;
    }

    $scope.viewAllAddressBook();
}

6. Address Book HTML

<div class="alert alert-error" ng-show="error">{{errorMessage}}</div>
<div class="row">
    <form ng-submit="addAddressBook(ab)">
        <div class="col-lg-8">
            <input class="form-control" placeholder="Enter First Name" type="text" ng-model="ab.firstName" required min="1" />
            <input class="form-control" placeholder="Enter Last Name" type="text" ng-model="ab.lastName" required min="1" />
            <input class="form-control" placeholder="Enter Phone" type="text" ng-model="ab.phone" required min="1" />
            <input class="form-control" placeholder="Enter Email" type="text" ng-model="ab.email" required min="1" />
        </div>
    </form>

    <button class="btn btn-primary" ng-disabled="!ab" ng-hide="editMode" ng-click="addAddressBook(ab)">Add Entry</button>
    <button type="btn btn-primary" class="btn btn-primary"
            ng-disabled="!ab" ng-show="editMode"
            ng-click="updateAddressBook(ab)">Save</button>
    <button type="btn btn-primary" class="btn btn-primary" ng-click="resetAddressBookField()">Reset</button>
</div>
<hr />

<div class="row">
    <div class="col-lg-8">
        <div class="form-group">
            <div class="input-group">
                <input type="text" class="form-control" placeholder="Search" id="search-query-3" ng-model="searchAddressBook">
                  <span class="input-group-btn">
                    <button type="submit" class="btn"><span class="fui-search"></span></button>
                  </span>
            </div>
        </div>
    </div>
</div>
<hr />

<div class="alert alert-info" style="width:400px;margin-left:100px;" ng-show="addressBooks.length == 0">
    No address book entry found
</div>
<table class="table table-bordered table-striped" ng-show="addressBooks.length > 0">
    <thead>
    <tr>
        <th style="text-align: center; width: 25px;">Delete</th>
        <th style="text-align: center; width: 25px;">Update</th>
        <th style="text-align: center;">First Name</th>
        <th style="text-align: center;">Last Name</th>
        <th style="text-align: center;">Phone Number</th>
        <th style="text-align: center;">Email</th>
    </tr>
    </thead>
    <tbody>
    <tr ng-repeat="addressBook in addressBooks">
        <td  style="width:70px;text-align:center;"><button class="btn btn-mini btn-danger" ng-click="deleteAddressBook(addressBooks.indexOf(addressBook))">Delete</button></td>
        <td  style="width:70px;text-align:center;"><button class="btn btn-mini btn-danger" ng-click="editAddressBook(addressBooks.indexOf(addressBook), addressBook)">Update</button></td>
        <td>{{addressBook.firstName}}</td><td>{{addressBook.lastName}}</td><td>{{addressBook.phone}}</td><td>{{addressBook.email}}</td>
    </tr>
    </tbody>
</table>
<button class="btn btn-danger"  ng-show="addressBooks.length >= 1" ng-click="deleteAllAddressBook()">Delete All Address Book</button>

Spring MVC AngularJs Todo List

Try it: http://cloudsole-angular.herokuapp.com
Clone it: https://github.com/thysmichels/cloudsole-angular

1. Todo Service
2. Todo Service Implementation
3. Todo Spring MVC Controller
4. Angular App.js
5. Angular TodoController
6. Todo html page

1. Todo Service

package com.cloudsole.angular.service;

import java.util.List;

/**
 * Created by tmichels on 8/1/14.
 */
public interface TodoService {
    public List<String> allTodos();
    public void addTodo(String todo);
    public void deleteTodo(String todo);
    public void deleteAll();
    public void updateTodo(int position, String todo);
}

2. Todo Service Implementation

package com.cloudsole.angular.service;

import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by tmichels on 8/1/14.
 */

@Service
public class TodoServiceImpl implements TodoService {

    List<String> todos = new ArrayList<String>();

    @Override
    public List<String> allTodos() {
        return todos;
    }

    @Override
    public void addTodo(String todo) {
        todos.add(todo);
    }

    @Override
    public void deleteTodo(String todo) {
        if (todos.contains(todo)){
            todos.remove(todo);
        }
    }

    @Override
    public void deleteAll() {
        todos.clear();
    }


    @Override
    public void updateTodo(int position, String todo) {
        todos.set(position, todo);
    }
}

3. Todo Spring MVC Controller

package com.cloudsole.angular.controller;

import com.cloudsole.angular.service.TodoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;

/**
 * Created by tmichels on 8/1/14.
 */

@Controller
@RequestMapping("/todo")
public class TodoController {

    @Autowired
    private TodoService todoService;

    @RequestMapping(value = "/all.json")
    public @ResponseBody List<String> viewAllTodos(){
        return todoService.allTodos();
    }

    @RequestMapping(value = "/add/{todo}", method = RequestMethod.POST)
    public @ResponseBody void addTodo(@PathVariable("todo") String todo){
        todoService.addTodo(todo);
    }

    @RequestMapping(value = "/delete/{todo}", method = RequestMethod.DELETE)
    public @ResponseBody void deleteTodo(@PathVariable("todo") String todo){
        todoService.deleteTodo(todo);
    }

    @RequestMapping(value = "/deleteAll", method = RequestMethod.DELETE)
    public @ResponseBody void deleteAllTodo(){
        todoService.deleteAll();
    }

    @RequestMapping(value="/update/{position}/{todo}", method = RequestMethod.PUT)
    public @ResponseBody void updateTodo(@PathVariable("position") String position, @PathVariable("todo") String todo){
        todoService.updateTodo(Integer.valueOf(position), todo);
    }

    @RequestMapping("/layout")
    public String getTodoPartialPage() {
        return "todo/layout";
    }
}

4. Angular App.js

'use strict';

var AngularSpringApp = {};

var App = angular.module('AngularSpringApp', ['AngularSpringApp.filters', 'AngularSpringApp.services', 'AngularSpringApp.directives', 'ngRoute', 'ui.bootstrap', 'ngTable', 'ui.ace', 'angularFileUpload']);

// Declare app level module which depends on filters, and services
App.config(['$routeProvider', function ($routeProvider) {

    $routeProvider.when('/todo', {
        templateUrl: 'todo/layout',
        controller: TodoController
    });
    $routeProvider.when('/address', {
        templateUrl: 'address/layout',
        controller: AddressBookController
    });
    $routeProvider.when('/table', {
        templateUrl: 'table/layout',
        controller: TableController
    });
    $routeProvider.when('/file', {
        templateUrl: 'file/layout',
        controller: FileController
    });
    $routeProvider.when('/editor', {
        templateUrl: 'editor/layout',
        controller: EditorController
    });
    $routeProvider.when('/rest', {
        templateUrl: 'restangular/layout',
        controller: RestController
    });
    $routeProvider.when('/force', {
        templateUrl: 'force/layout',
        controller: ForceController
    });

    $routeProvider.otherwise({redirectTo: '/todo'});
}]);

5. Angular TodoController


var TodoController = function($scope, $http){

    $scope.editMode = false;
    $scope.position = '';

    $scope.getAllTodos = function(){
        $scope.resetError();
        $http.get('todo/all.json').success(function(response){
            $scope.todos = response;
        }).error(function() {
            $scope.setError('Could not display all todos');
        });
    }

    $scope.addTodo = function(newTodo){
        $scope.resetError();
        $http.post('todo/add/' + newTodo).success(function(response){
            $scope.getAllTodos();
        }).error(function() {
            $scope.setError('Could add todo');
        });
        $scope.todoName = '';
    }

    $scope.deleteTodo = function(deleteTodo){
        $scope.resetError();
        $http.delete('todo/delete/'+deleteTodo).success(function(response){
            $scope.getAllTodos();
        }).error(function() {
            $scope.setError('Could not delete todo');
        });
    }

    $scope.deleteAllTodo = function(){
        $scope.resetError();
        $http.delete('todo/deleteAll').success(function(response){
            $scope.getAllTodos();
        }).error(function() {
            $scope.setError('Could not delete all todos');
        })
    }

    $scope.editTodo = function(position, todo){
        $scope.resetError();
        $scope.todoName = todo;
        $scope.position = position;
        $scope.editMode = true;
    }

    $scope.updateTodo = function(updateTodo){
        $scope.resetError();
        $http.put('todo/update/'+ $scope.position +'/'+updateTodo).success(function(response){
            $scope.getAllTodos();
            $scope.position = '';
            $scope.todoName = '';
            $scope.editMode = false;
        }).error(function(){
            $scope.setError('Could not update todo');
         })
    }

    $scope.resetTodoField = function() {
        $scope.resetError();
        $scope.todoName = '';
        $scope.editMode = false;
    };

    $scope.resetError = function() {
        $scope.error = false;
        $scope.errorMessage = '';
    };

    $scope.setError = function(message) {
        $scope.error = true;
        $scope.errorMessage = message;
    };

    $scope.getAllTodos();
}

6. Todo html page

<div class="alert alert-error" ng-show="error">{{errorMessage}}</div>
<div class="row">
    <form ng-submit="addTodo(todoName)">
    <div class="col-lg-8">
     <input class="form-control" placeholder="Enter Todo" type="text" ng-model="todoName" required min="1" />
    </div>
   </form>

    <button class="btn btn-primary" ng-disabled="!todoName" ng-hide="editMode" ng-click="addTodo(todoName)">Add Todo</button>
    <button type="btn btn-primary" class="btn btn-primary"
            ng-disabled="!todoName" ng-show="editMode"
            ng-click="updateTodo(todoName)">Save</button>
    <button type="btn btn-primary" class="btn btn-primary" ng-click="resetTodoField()">Reset</button>
</div>
 <hr />

<div class="row">
    <div class="col-lg-8">
        <div class="form-group">
            <div class="input-group">
                <input type="text" class="form-control" placeholder="Search" id="search-query-3" ng-model="searchTodo" typeahead="todo for todo in todos | filter:$viewValue | limitTo:8">
                  <span class="input-group-btn">
                    <button type="submit" class="btn"><span class="fui-search"></span></button>
                  </span>
            </div>
        </div>
    </div>
</div>
<hr />

<div class="alert alert-info" style="width:400px;margin-left:100px;" ng-show="todos.length == 0">
    No todos found
</div>
<table class="table table-bordered table-striped" ng-show="todos.length > 0">
    <thead>
    <tr>
        <th style="text-align: center; width: 25px;">Delete</th>
        <th style="text-align: center; width: 25px;">Update</th>
        <th style="text-align: center;">Todo</th>
    </tr>
    </thead>
    <tbody>
    <tr ng-repeat="todo in todos | filter:searchTodo">
        <td  style="width:70px;text-align:center;"><button class="btn btn-mini btn-danger" ng-click="deleteTodo(todo)">Delete</button></td>
        <td  style="width:70px;text-align:center;"><button class="btn btn-mini btn-danger" ng-click="editTodo(todos.indexOf(todo), todo)">Update</button></td>
        <td>{{todo}}</td>
    </tr>
    </tbody>
</table>
<button class="btn btn-danger"  ng-show="todos.length >= 1" ng-click="deleteAllTodo()">Delete All Todos</button>

Activiti REST Client Example

Activiti REST Client

package com.nuke.activiti.client;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONStringer;
import org.restlet.data.ChallengeScheme;
import org.restlet.data.MediaType;
import org.restlet.ext.json.JsonRepresentation;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.resource.ClientResource;
import org.slf4j.Logger;

/**
 * @author tmichels
 */
public class ActivitiClient {

	private static final Logger logger = org.slf4j.LoggerFactory.getLogger(NucleusClient.class);
	
	private static final String REST_URI = "http://activiti-dev.com:8090/api/activiti/v1";
	private static final String LDAP_USERNAME="xxxx";
	private static final String LDAP_PASSWORD="xxxx";
	
	private static ClientResource getClientResource(String uri) throws IOException{
		ClientResource clientResource = new ClientResource(uri);
		clientResource.setChallengeResponse(ChallengeScheme.HTTP_BASIC, LDAP_USERNAME, LDAP_PASSWORD);
        return clientResource;
	}
	
	public static List<String> getQueueNames(String username) throws JSONException, IOException{
		String authenticateUserUri = REST_URI + "/identity/users/"+username;
		Representation authenticateUserJSON = getClientResource(authenticateUserUri).get(MediaType.APPLICATION_JSON);
		JSONObject authenticateObject = new JSONObject(authenticateUserJSON.getText());
		logger.info("Get Queue Name: " + authenticateObject);
		if (!authenticateObject.opt("id").equals(null)) {
			List<String> queueForUser = new ArrayList<String>();
			String uri = REST_URI +"/repository/process-definitions";
			Representation response = getClientResource(uri).get(MediaType.APPLICATION_JSON);
			JSONObject object = new JSONObject(response.getText());
			JSONArray arr = (JSONArray) object.get("data");
			for (int i = 0; i < arr.length(); i++) {
				JSONObject ob = (JSONObject) arr.get(i);
				queueForUser.add(ob.get("name").toString());
			}
			return queueForUser;
		}
		return null;
	}

	public static String claimAndCompleteTaskByProcessIdAndActorName(String processInstanceId, String actorName) throws JSONException, IOException {
        try {
            String authenticateUserUri = REST_URI + "/identity/users/"+actorName;
            Representation authenticateUserJSON = getClientResource(authenticateUserUri).get(MediaType.APPLICATION_JSON);
            JSONObject authenticateObject = new JSONObject(authenticateUserJSON.getText());
            logger.info("AuthenticateObject: " + authenticateObject);
            if (!authenticateObject.opt("id").equals(null)) {
                String getTaskUri = REST_URI + "/runtime/tasks?candidate=" + actorName + "&size=1&order=asc&taskDefinitionKey=UnassignedLoan";
                Representation response = getClientResource(getTaskUri).get(MediaType.APPLICATION_JSON);
                JSONObject object = new JSONObject(response.getText());
                if (object != null) {
                    JSONArray arr = (JSONArray) object.get("data");
                    for (int i = 0; i < arr.length(); i++) {
                        JSONObject ob = (JSONObject) arr.get(i);
                        if (processInstanceId != null) {
                            if (ob.get("processDefinitionId").equals(processInstanceId)) {
                                logger.info("Returned task: " + ob);
                                if (ob.get("id") != null) {
                                    String claimUri = REST_URI + "/runtime/tasks/" + ob.get("id");
                                    logger.info("Claim URI: " + claimUri);
                                    JSONStringer jsAssignee = new JSONStringer();
                                    jsAssignee.object().key("assignee").value(actorName);
                                    jsAssignee.key("owner").value(actorName);
                                    jsAssignee.endObject();
                                    logger.info("jsAssignee: " + jsAssignee.toString());
                                    
                                    JSONStringer jsClaim = new JSONStringer();
                                    jsClaim.object().key("action").value("claim");
                                    jsClaim.endObject();
                                    logger.info("jsClaim: " + jsClaim.toString());
                                    
                                    JsonRepresentation jsonAssigneeRepresentation = new JsonRepresentation(jsAssignee);
                                    logger.info("jsonAssigneeRepresentation: " + jsonAssigneeRepresentation.getText());
                                    
                                    JsonRepresentation jsonClaimRepresentation = new JsonRepresentation(jsClaim);
                                    logger.info("jsonClaimRepresentation: " + jsonClaimRepresentation.getText());
                                    
                                    Representation assigneeResponse = getClientResource(claimUri).put(jsonAssigneeRepresentation);
                                    Representation claimResponse = getClientResource(claimUri).post(jsonClaimRepresentation);
                                    	
                                    logger.info("Assignee Response: " + assigneeResponse.getText());
                                    
                                    if (claimResponse.getText() == null) {
                                    	boolean completeTask = NucleusClient.completeTaskByIdWithVariables(ob.getString("description").toString(), actorName, null);
                                        logger.info("Complete Response: "  + completeTask);
                                        if (completeTask) {
                                        	 JSONObject taskByLoan = getTaskByLoanId(ob.getString("description").toString());
                                        	 JSONArray taskByLoanArray = (JSONArray) taskByLoan.get("data");
                                        	 if (!taskByLoanArray.isNull(0)) {
                                        		 JSONObject obTask = (JSONObject) taskByLoanArray.get(0);
                                            	 JSONStringer jsAssigneeAfterComplete = new JSONStringer();
                                            	 jsAssigneeAfterComplete.object().key("assignee").value(actorName);
                                            	 jsAssigneeAfterComplete.key("owner").value(actorName);
                                            	 jsAssigneeAfterComplete.endObject();
                                                 JsonRepresentation jsonAssigneeAfterCompleteRepresentation = new JsonRepresentation(jsAssigneeAfterComplete);
                                                 String claimAfterCompleteUri = REST_URI + "/runtime/tasks/" + obTask.get("id");
                                                 getClientResource(claimAfterCompleteUri).put(jsonAssigneeAfterCompleteRepresentation);
                                        	 }
                                            return ob.getString("description");
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                return null;
            }
            return null;
        }catch (Exception e){
        	logger.error("claimAndCompleteTaskByProcessIdAndActorName", e);
            return null;
        }
	}
	
	public static JSONObject getTaskByLoanId(String loanId) throws JSONException, IOException {
		String getTaskByLoanId = REST_URI +"/runtime/tasks?description=" + loanId + "&size=1";
        Representation response = getClientResource(getTaskByLoanId).get(MediaType.APPLICATION_JSON);
        JSONObject object = new JSONObject(response.getText());
        return object;
	}
	
	public static boolean completeTaskByIdWithVariables(String loanId, String actorName, Map<String, String> completeVariables) throws Exception {
        try {
            JSONObject loanjsonObjs = getTaskByLoanId(loanId);
            JSONArray loanArr = (JSONArray) loanjsonObjs.get("data");
            logger.info("LoanArr: " + loanArr);
            if (!loanArr.isNull(0) && loanArr.getJSONObject(0).has("id")) {
              JSONObject loanjsonObj = loanArr.getJSONObject(0);
          	  String uri = REST_URI + "/runtime/tasks/" + loanjsonObj.get("id").toString();

                JSONStringer jsComplete = new JSONStringer();
                jsComplete.object().key("action").value("complete");
              
                if (completeVariables!=null){
                    jsComplete.key("variables").array().object();
                    for (String completeVariable : completeVariables.keySet()) {
                        jsComplete.key("name").value(completeVariable).key("value").value(completeVariables.get(completeVariable));
                    }
                    jsComplete.endObject().endArray();
                }

                jsComplete.endObject();

                JsonRepresentation jsonCompleteRepresentation = new JsonRepresentation(jsComplete);
                logger.info("jsonCompleteRepresentation: " + jsonCompleteRepresentation.getText());
                if(completeVariables==null || !(loanArr.getJSONObject(0).getString("taskDefinitionKey").equals("SaveForLater") && completeVariables.get("disposition").equals("saveforlater"))) {
                	Representation completeResponse = getClientResource(uri).post(jsonCompleteRepresentation, MediaType.APPLICATION_JSON);
                	logger.info("Complete Response: " + completeResponse.getText());
                    if (completeResponse.getText()==null){
                    	if (completeVariables!=null && !completeVariables.get("disposition").equals("incomplete")) {
                    		 JSONObject taskByLoan = getTaskByLoanId(loanId);
                        	 JSONArray taskByLoanArray = (JSONArray) taskByLoan.get("data");
                        	 
                        	 if (!taskByLoanArray.isNull(0)) {
                        		 JSONObject obTask = (JSONObject) taskByLoanArray.get(0);
                         
                            	 JSONStringer jsAssigneeAfterComplete = new JSONStringer();
                            	 jsAssigneeAfterComplete.object().key("assignee").value(actorName);
                            	 jsAssigneeAfterComplete.key("owner").value(actorName);
                            	 jsAssigneeAfterComplete.endObject();
                                
                                 JsonRepresentation jsonAssigneeAfterCompleteRepresentation = new JsonRepresentation(jsAssigneeAfterComplete);
                                 String claimAfterCompleteUri = REST_URI + "/runtime/tasks/" + obTask.get("id");
                                 getClientResource(claimAfterCompleteUri).put(jsonAssigneeAfterCompleteRepresentation);
                        	 }
                    	}
                        return true;
                    }
                } else {
                	return true;
                }
            }
        }catch (Exception e){
          	e.printStackTrace();
              
        }
        return false;
	}
	
	public static String getProcessIdByName(String queueName) throws IOException, JSONException {
		String uri = REST_URI + "/repository/process-definitions";
		Representation response = getClientResource(uri).get(MediaType.APPLICATION_JSON);
		JSONObject object = new JSONObject(response.getText());
		if (object != null) {
			JSONArray arr = (JSONArray) object.get("data");
			for (int i = 0; i < arr.length(); i++) {
				JSONObject jsonObject = (JSONObject) arr.get(i);
				if (jsonObject.get("key").equals(queueName)) {
					logger.info("Returning processDefinitionId " + jsonObject.get("id"));
					return (String) jsonObject.get("id");
				}
			}
		}
		return null;
	}

	public static String createTaskByProcessId(String processDefinitionId, Map<String, String> taskVariables) throws Exception {
		String uri = REST_URI + "/runtime/process-instances";
		JSONStringer jsRequest = new JSONStringer();
		jsRequest.object().key("processDefinitionId").value(processDefinitionId).key("variables").array().object();
		for (String taskVariable : taskVariables.keySet()) {
			jsRequest.key("name").value(taskVariable).key("value").value(taskVariables.get(taskVariable));
		}
		jsRequest.endObject().endArray();
		jsRequest.endObject();
		Representation rep = new StringRepresentation(jsRequest.toString(), MediaType.APPLICATION_JSON);
		JSONObject jsObj = new JSONObject(getClientResource(uri).post(rep).getText());
		logger.info("Returned process: " + jsObj);
		if (jsObj.has("id")) {
			return  jsObj.getString("id");
		} else {
			return null;
		}
	}

	public static String getTaskIdByProcessIdAndActorName(String processInstanceId, String actorName) throws Exception {
		String uri = REST_URI + "/runtime/tasks?candidate=" +actorName;
		Representation response = getClientResource(uri).get(MediaType.APPLICATION_JSON);
		JSONObject object = new JSONObject(response.getText());
		if (object != null) {
			JSONArray arr = (JSONArray) object.get("data");
			for (int i = 0; i < arr.length(); i++) {
				JSONObject ob = (JSONObject) arr.get(i);
				if (ob.get("processDefinitionId").equals(processInstanceId)) {
					logger.info("Returned task: " + ob);
					logger.info("Returning taskId " + ob.get("id"));
					return (String) ob.get("id");
				}
			}
		}
		return null;
	}

	public static boolean claimTaskByIdAndActorName(String taskId, String actorName) throws Exception {
		String uri = REST_URI + "/runtime/tasks/" + taskId;

        JSONStringer jsClaim = new JSONStringer();
        jsClaim.object().key("action").value("claim");
        jsClaim.endObject();
        logger.info("jsClaim: " + jsClaim.toString());

        JsonRepresentation jsonClaimRepresentation = new JsonRepresentation(jsClaim);
        logger.info("jsonClaimRepresentation: " + jsonClaimRepresentation.getText());
		Representation claimResponse = getClientResource(uri).post(jsonClaimRepresentation, MediaType.APPLICATION_JSON);

        JSONStringer jsAssignee = new JSONStringer();
        jsAssignee.object().key("assignee").value(actorName);
        jsAssignee.key("owner").value(actorName);
        jsAssignee.endObject();
        logger.info("jsAssignee: " + jsAssignee.toString());
        
        JsonRepresentation jsonAssignRepresentation = new JsonRepresentation(jsAssignee);

        getClientResource(uri).put(jsonAssignRepresentation, MediaType.APPLICATION_JSON);

        return claimResponse.getText()==null;
	}


	@SuppressWarnings("unused")
	public static int getTaskCountByActorNameAndStatus(String actorName, String status) throws Exception {
		String uri = REST_URI + "/runtime/tasks?candidate=" + actorName + "&status=" + status;
		Representation response = getClientResource(uri).get(MediaType.APPLICATION_JSON);
		JSONObject object = new JSONObject(response.getText());
		if (object != null) {
			JSONArray arr = (JSONArray) object.get("data");
			logger.info("Tasklist " + actorName + " " + status + " size "	+ arr.length());
			return arr.length();
		}
		return -1;
	}
	
	public static List<String> taskQueryByActorNameBySizeAndOrder(String actorName,int size, String order, String status) throws Exception {
		List<String> taskForActor = new ArrayList<String>();
		String url = REST_URI + "/runtime/tasks?assignee="+ actorName +"&size=" + size + "&order="+order +"&status="+status;
		Representation response = getClientResource(url).get(MediaType.APPLICATION_JSON);
		if (response != null) {
			JSONObject object = new JSONObject(response.getText());
			if (object != null) {
				JSONArray arr = (JSONArray) object.get("data");
				for (int i = 0; i < arr.length(); i++) {
					JSONObject ob = (JSONObject) arr.get(i);
					taskForActor.add(ob.toString());
				}
			}
		}
		return taskForActor;
	}
}

Activiti REST Client Test

package com.nuke.activiti.client;

import static org.junit.Assert.*;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.json.JSONException;
import org.junit.Test;

import com.nuke.activiti.common.AbstractTest;

/**
 * @author tmichels
 */
public class ActivitiClientTest extends AbstractTest {
	
	@Test
	public void testGetQueueNamesAdmin() throws IOException, JSONException {
        List<String> queueNames = NucleusClient.getQueueNames("qatester_tools");
        for (String queueName : queueNames) {
            System.out.println(queueName);
        }
        assertNotNull(queueNames);
	}
	
	
	@Test
	public void testGetQueueNames() throws JSONException, IOException {
		List<String> queueNames = NucleusClient.getQueueNames("qatester_tools");
		for (String queueName : queueNames) {
			System.out.println(queueName);
		}
		assertNotNull(queueNames);
	}
	
	@Test
	public void testGetQueueTestEdgarNames() throws JSONException, IOException {
		List<String> queueNames = NucleusClient.getQueueNames("qatester_tools");
		for (String queueName : queueNames) {
			System.out.println(queueName);
		}
		assertNotNull(queueNames);
	}
	
	@Test
	public void testNewDiagram() throws IOException, JSONException {
		assertNotNull(NucleusClient.getProcessIdByName("underwritingQueue"));
		System.out.println("OUTPUT: " + NucleusClient.getProcessIdByName("bankVerificationQueue"));
		assertNotNull(NucleusClient.getProcessIdByName("bankVerificationQueue"));
	}
	
	
	@Test
	public void testWithUserInSameLDAPGroup() throws Exception {
		assertNotNull(NucleusClient.getTaskIdByProcessIdAndActorName(NucleusClient.getProcessIdByName("underwritingQueue"), "qatester_tools"));
	}
	
	@Test
	public void testGetQueueNamesNonReturn() throws JSONException, IOException {
		List<String> queueNames = NucleusClient.getQueueNames("dummy");
		assertNull(queueNames);
	}

    @Test
    public void testLoanComplete() throws Exception {
        String underwritingQueueProcessId = NucleusClient.getProcessIdByName("underwritingQueue");
        Map<String, String> processVariables = new HashMap<String, String>();
        processVariables.put("LoanId", "1");
        String processInstanceId = NucleusClient.createTaskByProcessId(underwritingQueueProcessId, processVariables);
        assertNotNull(processInstanceId);
        assertNotNull(NucleusClient.taskQueryByActorNameBySizeAndOrder("qatester_admin", 1, "asc", "open"));
        Map<String, String> completeVariables = new HashMap<String, String>();
        completeVariables.put("disposition", "complete");
        assertTrue(NucleusClient.completeTaskByIdWithVariables("1", "qatester_tools",completeVariables));
    }

 
    @Test
    public void testLoanInComplete() throws Exception{
        String underwritingQueueProcessId = NucleusClient.getProcessIdByName("underwritingQueue");
        Map<String, String> processVariables = new HashMap<String, String>();
        processVariables.put("LoanId", "2");
        NucleusClient.createTaskByProcessId(underwritingQueueProcessId, processVariables);
        assertTrue(NucleusClient.completeTaskByIdWithVariables("2", "qatester_admin", null));
        assertNotNull(NucleusClient.taskQueryByActorNameBySizeAndOrder("qatester_admin", 1, "asc", "open"));
        Map<String, String> completeVariables = new HashMap<String, String>();
        completeVariables.put("disposition", "incomplete");
        assertTrue(NucleusClient.completeTaskByIdWithVariables("2","qatester_tools", completeVariables));
        assertNotNull(NucleusClient.taskQueryByActorNameBySizeAndOrder("qatester_admin", 1, "asc", "open"));
    }

    @Test
    public void testSaveForLater() throws Exception{
        String underwritingQueueProcessId = NucleusClient.getProcessIdByName("underwritingQueue");
        Map<String, String> processVariables = new HashMap<String, String>();
        processVariables.put("LoanId", "3");
        String processInstanceId = NucleusClient.createTaskByProcessId(underwritingQueueProcessId, processVariables);
        System.out.println(processInstanceId);
        assertTrue(NucleusClient.completeTaskByIdWithVariables("3","qatester_tools", null));
        assertNotNull(NucleusClient.taskQueryByActorNameBySizeAndOrder("qatester_admin", 1, "asc", "open"));
        Map<String, String> completeVariables = new HashMap<String, String>();
        completeVariables.put("disposition", "saveforlater");
        assertTrue(NucleusClient.completeTaskByIdWithVariables("3", "qatester_tools",completeVariables));
    }


	@Test
	public void endToEndTest() throws Exception {
		String underwritingQueueProcessId = NucleusClient.getProcessIdByName("underwritingQueue");
		assertNotNull(underwritingQueueProcessId);
		Map<String, String> processVariables = new HashMap<String, String>();
		processVariables.put("LoanId", "00000000000");
		String processInstanceId = NucleusClient.createTaskByProcessId(underwritingQueueProcessId, processVariables);
		System.out.println("processInstanceId: " + underwritingQueueProcessId);
		assertNotNull(processInstanceId);
		String taskId = NucleusClient.getTaskIdByProcessIdAndActorName(NucleusClient.getProcessIdByName("underwritingQueue"), "qatester_tools");
		assertNotNull(taskId);
		assertNotNull(NucleusClient.claimTaskByIdAndActorName(taskId, "qatester_tools"));

		assertNotNull(NucleusClient.completeTaskByIdWithVariables(taskId,"qatester_tools", null));

		assertNotNull(NucleusClient.getTaskCountByActorNameAndStatus("qatester_tools", "closed"));

        Map<String, String> completeVariables = new HashMap<String, String>();
        completeVariables.put("disposition", "saveforlater");
        NucleusClient.completeTaskByIdWithVariables(taskId,"qatester_tools", completeVariables);
        assertNotNull(NucleusClient.getTaskCountByActorNameAndStatus("qatester_tools", "closed"));
	}
	
	
	@Test
	public void testUserInSameLDAPGroup() throws Exception {
		assertNotNull(NucleusClient.getTaskIdByProcessIdAndActorName(NucleusClient.getProcessIdByName("underwritingQueue"), "qatester_tools"));
	}
	
	
	@Test
	public void testGetProcessIdByName() throws Exception {
		String queueProcessId = NucleusClient.getProcessIdByName("underwritingQueue");
		assertNotNull(queueProcessId);
	}
	
	@Test
	public void testCreateTaskByProcessId() throws Exception {
		String underwritingQueueProcessId = NucleusClient.getProcessIdByName("underwritingQueue");
		assertNotNull(underwritingQueueProcessId);
		Map<String, String> processVariables = new HashMap<String, String>();
		processVariables.put("LoanId", "332233555");
		String createComplete = NucleusClient.createTaskByProcessId(underwritingQueueProcessId, processVariables);
		System.out.println("CREATE COMPLETE: " + createComplete);
		assertNotNull(createComplete);
	}
	
	@Test
	public void testTaskByActorName() throws Exception {
		String processId = NucleusClient.getProcessIdByName("underwritingQueue");
		String taskId = NucleusClient.getTaskIdByProcessIdAndActorName(processId, "qatester_tools");
		assertNotNull(taskId);
	}
	
	@Test
	public void testClaimTaskById() throws Exception {
		String processId = NucleusClient.getProcessIdByName("underwritingQueue");
		String taskId = NucleusClient.getTaskIdByProcessIdAndActorName(processId, "qatester_tools");
		assertNotNull(NucleusClient.claimTaskByIdAndActorName(taskId, "qatester_tools"));
	}
	
	@Test
	public void testCompleteTaskById() throws Exception {
		String processId = NucleusClient.getProcessIdByName("underwritingQueue");
		Map<String, String> processVariables = new HashMap<String, String>();
		processVariables.put("LoanId", "3333333333");
		NucleusClient.createTaskByProcessId(processId, processVariables);
		String taskId = NucleusClient.getTaskIdByProcessIdAndActorName(processId, "qatester_tools");
		Map<String, String> completeVariables = new HashMap<String, String>();
		completeVariables.put("disposition", "complete");
		assertNotNull(NucleusClient.completeTaskByIdWithVariables(taskId,"qatester_tools", completeVariables));
	}
	
	@Test
	public void testIncompleteTaskById() throws Exception{
		String processId = NucleusClient.getProcessIdByName("underwritingQueue");
		Map<String, String> processVariables = new HashMap<String, String>();
		processVariables.put("LoanId", "4444444444");
		NucleusClient.createTaskByProcessId(processId, processVariables);
		String taskId = NucleusClient.getTaskIdByProcessIdAndActorName(processId, "qatester_tools");
		Map<String, String> completeVariables = new HashMap<String, String>();
		completeVariables.put("disposition", "incomplete");
		assertNotNull(NucleusClient.completeTaskByIdWithVariables(taskId,"qatester_tools", completeVariables));
	}
	
	@Test
	public void testSaveForLaterTaskById() throws Exception {
		String processId = NucleusClient.getProcessIdByName("underwritingQueue");
		Map<String, String> processVariables = new HashMap<String, String>();
		processVariables.put("LoanId", "5555555555");
		String creatProcessId = NucleusClient.createTaskByProcessId(processId, processVariables);
		System.out.println("CreatedProcessId: " + creatProcessId);
		String taskId = NucleusClient.getTaskIdByProcessIdAndActorName(processId, "qatester_tools");
		Map<String, String> completeVariables = new HashMap<String, String>();
		completeVariables.put("disposition", "saveforlater");
		assertNotNull(NucleusClient.completeTaskByIdWithVariables(taskId,"qatester_tools", completeVariables));
	}
	
	@Test
	public void testGetTaskCountByActorNameAndStatus() throws Exception {
		int taskCount = NucleusClient.getTaskCountByActorNameAndStatus("qatester_tools", "open");
		assertNotNull(taskCount);
	}
	
	@Test
	public void testTaskQueryForActorNameBySizeAndOrder() throws Exception {
		List<String> taskIds = NucleusClient.taskQueryByActorNameBySizeAndOrder("qatester_tools", 5, "asc", "open");
		for (String taskId : taskIds) {
			System.out.println("TASKID: " + taskId);
		}
		assertNotNull(taskIds);
	}
	
	@Test
	public void testGetTaskClaimAndCompleteTaskByProcessIdAndActorName() throws JSONException, IOException {
		assertNotNull(NucleusClient.claimAndCompleteTaskByProcessIdAndActorName(NucleusClient.getProcessIdByName("underwritingQueue"), "qatester_tools"));
	}

    @Test
    public void testGetTaskClaimAndCompleteTaskByProcessIdAndActorNameWithWrongActorName() throws Exception{
        assertNull(NucleusClient.claimAndCompleteTaskByProcessIdAndActorName(NucleusClient.getProcessIdByName("underwritingQueue"), "dummy"));
    }

    @Test
    public void testGetTaskClaimAndCompleteTaskByProcessIdAndActorNameWithWrongProcessName() throws Exception{
        assertNull(NucleusClient.claimAndCompleteTaskByProcessIdAndActorName(NucleusClient.getProcessIdByName("dummy"), "dummy"));
    }


    @Test
    public void testProccessIdReturnNullWhenInvalid() throws IOException, JSONException {
        assertNull(NucleusClient.getProcessIdByName("dummy"));
    }

	@Test
	public void testGetTaskByLoanId() throws JSONException, IOException {
		assertNotNull(NucleusClient.getTaskByLoanId("259190367").getJSONArray("data"));
	}
	
	@Test
	public void testSaveForlater() throws Exception {
		Map<String, String> completeVariables = new HashMap<String, String>();
		completeVariables.put("disposition", "complete");
		NucleusClient.completeTaskByIdWithVariables("685363", "qatester_tools", completeVariables);
	}
	
	@Test
	public void testSaveForLaterIfAlreadySaveForLater() throws Exception {
		String processId = NucleusClient.getProcessIdByName("underwritingQueue");
		String taskId = NucleusClient.getTaskIdByProcessIdAndActorName(processId, "qatester_tools");
		System.out.println("TaskId: " + taskId);
		Map<String, String> completeVariables = new HashMap<String, String>();
		completeVariables.put("disposition", "incomplete");
		assertNotNull(NucleusClient.completeTaskByIdWithVariables("1111111111","qatester_tools", completeVariables));
	}
}

Integrating Activiti with Active Directory

Integrating Activiti with LDAP can be tricky. Through trail and error I got Active Directory working with Activit. The configuration may not be exactly the same for your organization, all depends on how your LDAP is setup.

package com.nuke.ldap;

import java.util.HashMap;
import java.util.Map;

import org.activiti.ldap.LDAPConfigurator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

import com.nuke.activiti.annotations.ActivitiProd;

@Configuration
@ActivitiProd
public class LDAPProdConfiguration {

	@Value("${LDAP_URL:}")
	private String ldapUrl;

	@Value("${LDAP_SERVICE_ACCOUNT_NAME:}")
    private String ldapServiceAccountUserName;

	@Value("${LDAP_SERVICE_ACCOUNT_CN:}")
    private String ldapServiceAccountUserNameCn;
    
	@Value("${LDAP_SERVICE_ACCOUNT_PASSWORD:}")
    private String ldapServiceAccountPassword;

	@Value("${LDAP_SEARCH_FILTER:}")
    private String ldapSearchFilter;

	@Bean(name="ldapProd")
	public LDAPConfigurator LDAProdPConfig(){
		LDAPConfigurator ldapProdConfig = new LDAPConfigurator();
		ldapProdConfig.setServer(ldapUrl);
		ldapProdConfig.setUser(ldapServiceAccountUserNameCn);
		ldapProdConfig.setPassword(ldapServiceAccountPassword);
		
		ldapProdConfig.setBaseDn("OU=Security Groups,DC=Corp,DC=internal,DC=us"); 
		ldapProdConfig.setUserBaseDn("OU=Service Accounts,DC=Corp,DC=internal,DC=us");
		ldapProdConfig.setGroupBaseDn("OU=Security Groups,DC=Corp,DC=internal,DC=us");
		
		ldapProdConfig.setQueryUserByUserId("(&(objectClass=user)(sAMAccountName={0}))");
		ldapProdConfig.setQueryUserByFullNameLike("(&(objectClass=user)(|({0}=*{1}*)({2}=*{3}*)))");
		ldapProdConfig.setQueryGroupsForUser("(&(objectClass=group)(member={0}))");
		
		Map<String, String> connectionMap = new HashMap<String, String>();
		connectionMap.put("InitialDirContext", "Context.REFERRAL");
		ldapProdConfig.setCustomConnectionParameters(connectionMap);
		
		ldapProdConfig.setUserIdAttribute("cn");
		ldapProdConfig.setUserFirstNameAttribute("givenName");
		ldapProdConfig.setUserLastNameAttribute("sn");
		
		ldapProdConfig.setGroupIdAttribute("sAMAccountName");
		ldapProdConfig.setGroupNameAttribute("sAMAccountName");
		
		return ldapProdConfig;
	}
}

Dropbox OAuth 2.0 Scribe Java Example

Dropbox OAuthServiceConfig and OAuthServiceProvider Bean

<bean id="dropboxServiceConfig" class="com.example.oauth.OAuthServiceConfig">
		<constructor-arg value="xxx" />
		<constructor-arg value="xxx"/>
		<constructor-arg value="https://www.example.com/oauth/dropbox"/>
		<constructor-arg value="com.example.oauth.DropBoxApi20"/>
	</bean>
	
	<bean id="dropboxServiceProvider" class="com.example.oauth.OAuthServiceProvider">
		<constructor-arg name="config" ref="dropboxServiceConfig" />
	</bean>

Dropbox OAuth Spring MVC Controller

package com.example.oauth.controller;

import static org.springframework.web.context.request.RequestAttributes.SCOPE_SESSION;

import java.util.Map;

import javax.servlet.http.HttpSession;

import org.scribe.model.Token;
import org.scribe.model.Verifier;
import org.scribe.oauth.OAuthService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.context.request.WebRequest;

import com.example.oauth.OAuthServiceProvider;

@Controller
@RequestMapping("/oauth/dropbox")
public class DropboxController {
	
	@Autowired
	@Qualifier("dropboxServiceProvider")
	private OAuthServiceProvider dropboxServiceProvider;
	
	private static final Token EMPTY_TOKEN = null;
	
	@RequestMapping(value = "/login-dropbox", method = RequestMethod.GET)
	public String loginToDropBox(Map<String, Object> map, WebRequest request) {
		OAuthService service = dropboxServiceProvider.getService();
		String authUrl = service.getAuthorizationUrl(EMPTY_TOKEN);
		System.out.println("RequestToken: " + authUrl);
		return "redirect:" + authUrl;
	}

	@RequestMapping(value = { "" }, method = RequestMethod.GET)
	public String callback(
			@RequestParam(value = "oauth_token", required = false) String oauthToken,
			@RequestParam(value = "code", required = false) String oauthVerifier,
			WebRequest request, Map<String, Object> map) {

		OAuthService service = dropboxServiceProvider.getService();

		// getting access token
		Verifier verifier = new Verifier(oauthVerifier);
		Token accessToken = service.getAccessToken(EMPTY_TOKEN, verifier);

		// store access token as a session attribute
		request.setAttribute("oauthAccessToken", accessToken, SCOPE_SESSION);

		ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder
				.currentRequestAttributes();
		HttpSession session = attr.getRequest().getSession(false); // create a
																	// new
																	// session
		session.setAttribute("accessToken", accessToken);

		return "settings";
	}
}

DropBoxApi20 extends DefaultApi20

package com.example.oauth;

import org.scribe.builder.api.DefaultApi20;
import org.scribe.extractors.AccessTokenExtractor;
import org.scribe.extractors.JsonTokenExtractor;
import org.scribe.model.OAuthConfig;
import org.scribe.model.Verb;

public class DropBoxApi20 extends DefaultApi20 {

	@Override
	public String getAccessTokenEndpoint() {
		return "https://api.dropbox.com/1/oauth2/token?grant_type=authorization_code";
	}

	@Override
	public String getAuthorizationUrl(OAuthConfig config) {
		// TODO Auto-generated method stub
		return String.format("https://www.dropbox.com/1/oauth2/authorize?client_id=%s&response_type=code&redirect_uri=%s", config.getApiKey(), config.getCallback());
	}

	 @Override
	 public Verb getAccessTokenVerb(){
	       return Verb.POST;
	 }
	 
	@Override
    public AccessTokenExtractor getAccessTokenExtractor() {
        return new JsonTokenExtractor();
    }
}

Follow

Get every new post delivered to your Inbox.

Join 291 other followers

%d bloggers like this: