View Javadoc

1   /*
2    * Copyright 2009 The Kuali Foundation
3    * 
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    * http://www.opensource.org/licenses/ecl2.php
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.kew.clientapp;
17  
18  import java.security.AccessController;
19  import java.security.PrivilegedAction;
20  import java.util.List;
21  
22  import javax.xml.namespace.QName;
23  
24  import org.apache.log4j.Logger;
25  import org.junit.Test;
26  import org.kuali.rice.core.config.Config;
27  import org.kuali.rice.core.config.ConfigContext;
28  import org.kuali.rice.core.config.JAXBConfigImpl;
29  import org.kuali.rice.core.config.SimpleConfig;
30  import org.kuali.rice.core.exception.RiceRuntimeException;
31  import org.kuali.rice.core.resourceloader.GlobalResourceLoader;
32  import org.kuali.rice.core.resourceloader.ResourceLoader;
33  import org.kuali.rice.core.resourceloader.SpringResourceLoader;
34  import org.kuali.rice.kew.config.ThinClientResourceLoader;
35  import org.kuali.rice.kew.dto.RouteHeaderDTO;
36  import org.kuali.rice.kew.test.KEWTestCase;
37  import org.kuali.rice.kim.bo.entity.dto.KimPrincipalInfo;
38  import org.kuali.rice.kim.bo.group.dto.GroupInfo;
39  
40  /**
41   * 
42   * Test case that confirms functionality of the KEW thin client.  All configuration for
43   * the thin client is external, so this test should be helpful as a model for setting
44   * up thin client mode. 
45   * 
46   * One potentially confusing element here is the use of a ClassLoader, but all it is really
47   * there for is to allow us to bind the thin client configuration in the ConfigContext while
48   * at the same time running a rice instance with its own config.
49   * 
50   * @author Kuali Rice Team (rice.collab@kuali.org)
51   *
52   */
53  public class ThinClientTest extends KEWTestCase {
54  	private static final Logger LOG = Logger.getLogger(ThinClientTest.class);
55  
56  	/**
57  	 * configuration files used in this test 
58  	 */
59  	private static final String CONFIG_FILE = "classpath:/org/kuali/rice/kew/clientapp/thin-client-app-config.xml";
60  	private static final String SPRING_BEANS_FILE = "classpath:/org/kuali/rice/kew/clientapp/ThinClientSpringBeans.xml";
61  
62  	private static final String KIM_PRINCIPAL_NAME = "testuser1";
63  
64  	private static SpringResourceLoader thinClientResourceLoader = new SpringResourceLoader(new QName("ThinClientTest"), 
65  			SPRING_BEANS_FILE);
66  	
67  	private ClassLoader ourClassLoader = null;
68  	private ClassLoader parentClassLoader = null;
69  	
70  	public ThinClientTest() {
71  	}
72  
73  	@Override
74  	public void setUp() throws Exception {
75  		super.setUp();
76  
77  		// put our own ClassLoader in place
78  		ourClassLoader = AccessController.doPrivileged(new DelegatingClassLoaderCreater());
79  
80  		parentClassLoader = Thread.currentThread().getContextClassLoader();
81  		Thread.currentThread().setContextClassLoader(ourClassLoader);
82  
83  		try {
84  			//Config config = new SimpleConfig(CONFIG_FILE);
85  			Config config = new JAXBConfigImpl(CONFIG_FILE);
86  			config.parseConfig();
87  			// initialize our config using properties bound to our custom classloader
88  			ConfigContext.init(ourClassLoader, config);
89  
90  			thinClientResourceLoader.start();
91  
92  		} catch (Exception e) {
93  			LOG.error("Failed to set up thin client test", e);
94  			throw new RiceRuntimeException(e);
95  		}
96  	}
97  
98  	@Override
99  	public void tearDown() throws Exception {
100 		// put the original ClassLoader back for the current thread
101 		Thread.currentThread().setContextClassLoader(parentClassLoader);
102 		// remove the reference to our config from the ConfigContext map
103 		ConfigContext.overrideConfig(ourClassLoader, null);
104 		
105 		// I can't imagine this is necessary
106 		ourClassLoader = null;
107 		thinClientResourceLoader = null;
108 
109 		super.tearDown();
110 	}
111 
112 	@Test
113 	public void testThinClientServices() throws Exception {
114 		//verify the ThinClientResourceLoader is in the GRL.
115 		ResourceLoader rl = GlobalResourceLoader.getResourceLoader();
116 		List<ResourceLoader> resourceLoaders = rl.getResourceLoaders();
117 		ResourceLoader tempThinRL = rl.getResourceLoaders().get(0);
118 		assertTrue("First resource loader should be thin", tempThinRL instanceof ThinClientResourceLoader);
119 		ThinClientResourceLoader thinRL = (ThinClientResourceLoader)tempThinRL;
120 
121 		// test KIM identity service
122 		KimPrincipalInfo principal = null;
123 		principal = thinRL.getIdentityService().getPrincipalByPrincipalName(KIM_PRINCIPAL_NAME);
124 		assertTrue(principal.getPrincipalName().equals(KIM_PRINCIPAL_NAME));
125 
126 		// test KIM group service
127 		List<GroupInfo> groups = thinRL.getGroupService().getGroupsForPrincipal(principal.getPrincipalId());
128 		assertNotNull(groups);
129 		assertTrue(groups.size() > 0);
130 
131 		// test Workflow
132 		RouteHeaderDTO routeHeader = new RouteHeaderDTO();
133 		routeHeader.setDocTypeName("RiceDocument");
134 		routeHeader = thinRL.getWorkflowDocument().createDocument(principal.getPrincipalId(), routeHeader);
135 		assertTrue(principal.getPrincipalId().equals(routeHeader.getInitiatorPrincipalId()));
136 	}
137 
138 	/**
139 	 * a privileged action to create a new classloader with our thread's classloader as its parent 
140 	 * 
141 	 * @author Kuali Rice Team (rice.collab@kuali.org)
142 	 *
143 	 */
144 	private class DelegatingClassLoaderCreater implements PrivilegedAction<ClassLoader> {
145 		public ClassLoader run() {
146 			return new DelegatingClassLoader(Thread.currentThread().getContextClassLoader());
147 		};
148 	}
149 
150 	/**
151 	 * a very minimal classloader to allow us to bind our thin client cofiguration 
152 	 * 
153 	 * @author Kuali Rice Team (rice.collab@kuali.org)
154 	 *
155 	 */
156 	private class DelegatingClassLoader extends ClassLoader {
157 		
158 		// silly default constructor so that Surefire doesn't get messed up
159 		// TODO: remove when http://jira.codehaus.org/browse/SUREFIRE-535 is fixed
160 		public DelegatingClassLoader() { }
161 
162 		public DelegatingClassLoader(ClassLoader parent) {
163 			super(parent);
164 		}
165 	}
166 
167 }
168