View Javadoc

1   /*
2    * Copyright (c) 2005 Regents of the University of California (Regents). Created
3    * by TELS, Graduate School of Education, University of California at Berkeley.
4    *
5    * This software is distributed under the GNU Lesser General Public License, v2.
6    *
7    * Permission is hereby granted, without written agreement and without license
8    * or royalty fees, to use, copy, modify, and distribute this software and its
9    * documentation for any purpose, provided that the above copyright notice and
10   * the following two paragraphs appear in all copies of this software.
11   *
12   * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
13   * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
14   * PURPOSE. THE SOFTWAREAND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
15   * HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
16   * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
17   *
18   * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
19   * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
20   * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
21   * REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22   */
23  package net.sf.sail.common.persistance.memory;
24  
25  import java.io.PrintStream;
26  import java.util.ArrayList;
27  import java.util.Collection;
28  import java.util.Date;
29  import java.util.HashMap;
30  import java.util.Iterator;
31  import java.util.List;
32  import java.util.Map;
33  import java.util.Set;
34  import java.util.logging.Logger;
35  
36  import javax.xml.parsers.DocumentBuilder;
37  import javax.xml.parsers.DocumentBuilderFactory;
38  import javax.xml.transform.OutputKeys;
39  import javax.xml.transform.Result;
40  import javax.xml.transform.Source;
41  import javax.xml.transform.Transformer;
42  import javax.xml.transform.TransformerException;
43  import javax.xml.transform.TransformerFactory;
44  import javax.xml.transform.dom.DOMSource;
45  import javax.xml.transform.stream.StreamResult;
46  
47  import net.sf.sail.core.beans.Pod;
48  import net.sf.sail.core.beans.SessionContext;
49  import net.sf.sail.core.beans.UnknownPodException;
50  import net.sf.sail.core.beans.service.AgentService;
51  import net.sf.sail.core.curnit.Curnit;
52  import net.sf.sail.core.entity.AgentSet;
53  import net.sf.sail.core.entity.IAgent;
54  import net.sf.sail.core.entity.ISock;
55  import net.sf.sail.core.entity.Rim;
56  import net.sf.sail.core.entity.Role;
57  import net.sf.sail.core.entity.UnsupportedRimShapeException;
58  import net.sf.sail.core.entity.User;
59  import net.sf.sail.core.uuid.UserUuid;
60  
61  import org.w3c.dom.CDATASection;
62  import org.w3c.dom.Document;
63  import org.w3c.dom.Element;
64  
65  public class MemoryPersistenceImpl 
66  	implements AgentService {
67  	/**
68  	 * Logger for this class
69  	 */
70  	private static final Logger logger = Logger
71  			.getLogger(MemoryPersistenceImpl.class.getName());
72  
73  	Map<Role,AgentSet> rolesToAgents = new HashMap<Role,AgentSet>();
74  
75  	Map<SockKey,ISock<Object>> socks = new HashMap<SockKey,ISock<Object>>();
76  
77  	Map<UserUuid,AgentSet> usersToAgents = new HashMap<UserUuid,AgentSet>();
78  
79  	Map<Rim<Object>, AgentSet> rimsToAgents = new HashMap<Rim<Object>, AgentSet>();
80  
81  	/**
82  	 * Just a plain old list of agents nothing fancy like the maps above
83  	 */
84  	List<IAgent> agents = new ArrayList<IAgent>();
85  	
86  	/**
87  	 * A sock is specified by an MemoryAgent,Rim tuple
88  	 * 
89  	 * @author turadg
90  	 */
91  	static class SockKey<T> {
92  		IAgent agent;
93  
94  		Rim<T> rim;
95  
96  		SockKey(Rim<T> rim, IAgent agent) {
97  			if (rim == null)
98  				throw new IllegalArgumentException("rim is null");
99  			if (agent == null)
100 				throw new IllegalArgumentException("agent is null");
101 			this.rim = rim;
102 			this.agent = agent;
103 		}
104 
105 		@Override
106 		public int hashCode() {
107 			return agent.hashCode() * 43 + rim.hashCode();
108 		}
109 
110 		@SuppressWarnings("unchecked")
111 		@Override
112 		public boolean equals(Object obj) {
113 			if (!(obj instanceof SockKey))
114 				return false;
115 			SockKey sk = (SockKey) obj;
116 			return this.rim == sk.rim && this.agent == sk.agent;
117 		}
118 
119 		@Override
120 		public String toString() {
121 			return "SockKey[" + rim + "," + agent + "]";
122 		}
123 	}
124 
125 	public AgentSet getAgentsInRole(Role role) {
126 		AgentSet agentSet = rolesToAgents.get(role);
127 		if (agentSet == null)
128 			agentSet = new AgentSet();
129 		return agentSet;
130 	}
131 
132 	@SuppressWarnings("unchecked")
133 	public <T> ISock<T> getSock(Rim<T> rim, IAgent agent) throws UnsupportedRimShapeException {
134 		if (rim == null)
135 			throw new IllegalArgumentException("getSock() received null rim");
136 		if (agent == null)
137 			throw new IllegalArgumentException("getSock() received null agent");
138 
139 		SockKey<T> key = new SockKey<T>(rim, agent);
140 		ISock sock = socks.get(key);
141 		if (sock == null) {
142 			Class<?> shape = rim.getShape();
143 			if (shape == String.class) {
144 				sock = new MemorySock<T>(rim);
145 			} else
146 				throw new UnsupportedRimShapeException(rim);
147 			socks.put(key, sock);
148 			registerRimUse(rim, agent);
149 		}
150 		return sock;
151 	}
152 
153 	/**
154 	 * @param rim
155 	 * @param agent
156 	 */
157 	@SuppressWarnings("unchecked")
158 	private void registerRimUse(Rim rim, IAgent agent) {
159 		AgentSet agents = rimsToAgents.get(rim);
160 		if (agents == null) {
161 			agents = new AgentSet();
162 			rimsToAgents.put(rim, agents);
163 		}
164 		agents.add(agent);
165 	}
166 
167 	/**
168 	 * @param agent
169 	 */
170 	protected void addAgent(MemoryAgent agent) {
171 		AgentSet agentSet = rolesToAgents.get(agent.getRole());
172 		if (agentSet == null) {
173 			agentSet = new AgentSet();
174 			rolesToAgents.put(agent.getRole(), agentSet);
175 		}
176 		agentSet.add(agent);
177 
178 		UserUuid[] users = agent.getUserArray();
179 		for (UserUuid element : users) {
180 			recordUserMembership(element, agent);
181 		}
182 		
183 		agents.add(agent);
184 	}
185 
186 	private void recordUserMembership(UserUuid user, IAgent agent) {
187 		AgentSet existingAgents = usersToAgents.get(user);
188 		if (existingAgents == null) {
189 			existingAgents = new AgentSet();
190 			usersToAgents.put(user, existingAgents);
191 		}
192 		if (!existingAgents.contains(agent))
193 			existingAgents.add(agent);
194 	}
195 
196 	String[] getKnownRoles() {
197 		Set<Role> roleSet = rolesToAgents.keySet();
198 		String[] roleArray = new String[roleSet.size()];
199 		roleSet.toArray(roleArray);
200 		return roleArray;
201 	}
202 
203 	public AgentSet getAgentsOfUser(User user) {
204 		AgentSet agentSet = new AgentSet();
205 		for (IAgent agent : agents) {
206 			UserUuid userIds[] = agent.getUserArray();
207 			for (UserUuid userId : userIds) {
208 				if(user.getUserUUID().equals(userId) &&
209 						!agentSet.contains(agent)){
210 					agentSet.add(agent);
211 				}
212 			}
213 		}
214 		
215 		return agentSet;
216 	}
217 
218 	/**
219 	 * Dump to out in SSDIF representation.
220 	 */
221 	public void dump(SessionContext session, PrintStream out) {
222 		Document document;
223 		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
224 		DocumentBuilder builder = null;
225 		try {
226 			builder = factory.newDocumentBuilder();
227 		} catch (Exception e) {
228 			// how can this fail?
229 			logger.severe("SessionContext, PrintStream -  : exception: " + e); //$NON-NLS-1$
230 		}
231 
232 		document = builder.newDocument();
233 		Element root = document.createElement("ssdif");
234 		document.appendChild(root);
235 
236 		Element authorData = buildAuthorDataElement(session, document);
237 		root.appendChild(authorData);
238 
239 		Element sessionElement = buildSessionElement(session, document);
240 		root.appendChild(sessionElement);
241 
242 		try {
243 			writeDocument(document, out);
244 		} catch (TransformerException e) {
245 			// TODO Auto-generated catch block
246 			logger.severe("SessionContext, PrintStream -  : exception: " + e); //$NON-NLS-1$
247 		}
248 	}
249 
250 	/**
251 	 * @param doc
252 	 * @return
253 	 */
254 	private Element buildSessionElement(SessionContext session, Document doc) {
255 		Element sessionElement = doc.createElement("session");
256 
257 		sessionElement.setAttribute("sessionId", session.getSessionId()
258 				.toString());
259 
260 		Date startTime = session.getStartTime();
261 		if (startTime != null)
262 			sessionElement.setAttribute("startTime", startTime.toGMTString());
263 		Date stopTime = session.getStopTime();
264 		if (stopTime != null)
265 			sessionElement.setAttribute("stopTime", stopTime.toGMTString());
266 
267 		Element ofrun = doc.createElement("of-run");
268 		ofrun.setAttribute("idref", "run1");
269 		sessionElement.appendChild(ofrun);
270 
271 		Element rimsElement = doc.createElement("rims");
272 
273 		// for each used Rim
274 		for (Rim<Object> rim : rimsToAgents.keySet()) {
275 			Element rimElement = doc.createElement("rim");
276 			String rimName = rim.getName();
277 			if (rimName == null)
278 				throw new NullPointerException("null rimName during dump");
279 			rimElement.setAttribute("id", rimName);
280 			// FIX how to find the Pod for a given Rim?
281 			rimElement.setAttribute("pod", "not implemented");
282 			AgentSet agents = rimsToAgents.get(rim);
283 			for (Iterator<?> iter2 = agents.iterator(); iter2.hasNext();) {
284 				MemoryAgent agent = (MemoryAgent) iter2.next();
285 				Element sockElement = doc.createElement("sock");
286 				// FIX agent local id?
287 				sockElement.setAttribute("agent", agent.toString());
288 				SockKey<Object> sockKey = new SockKey<Object>(rim, agent);
289 				ISock<Object> sock = socks.get(sockKey);
290 				for (Object value : sock) {
291 					Element entry = doc.createElement("entry");
292 					// FIX record time of each sock entry
293 					entry.setAttribute("time", "not implemented");
294 					// FIX serialize objects a more reliable way
295 					CDATASection section = doc.createCDATASection(value
296 							.toString());
297 					entry.appendChild(section);
298 					sockElement.appendChild(entry);
299 				}
300 				rimElement.appendChild(sockElement);
301 			}
302 			rimsElement.appendChild(rimElement);
303 		}
304 		sessionElement.appendChild(rimsElement);
305 
306 		return sessionElement;
307 	}
308 
309 	/**
310 	 * @param document
311 	 * @param out
312 	 * @throws TransformerException
313 	 */
314 	private void writeDocument(Document document, PrintStream out)
315 			throws TransformerException {
316 		TransformerFactory xformFactory = TransformerFactory.newInstance();
317 		Transformer idTransform = xformFactory.newTransformer();
318 		idTransform.setOutputProperty(
319 				"{http://xml.apache.org/xslt}indent-amount", "4");
320 		idTransform.setOutputProperty(OutputKeys.INDENT, "yes");
321 		Source input = new DOMSource(document);
322 		Result output = new StreamResult(out);
323 		idTransform.transform(input, output);
324 	}
325 
326 	/**
327 	 * @param doc
328 	 * @return
329 	 * @throws UnknownPodException 
330 	 */
331 	private Element buildAuthorDataElement(SessionContext session, Document doc) {
332 		Element authorData = doc.createElement("author-data");
333 
334 		// This persistanceImpl will only work with original curnit implementation.
335 		Curnit curnit = (Curnit) session.getOffering().getCurnit();
336 		int curnit_index = indexOf(curnit);
337 		Element curnitRef = doc.createElement("curnitRef");
338 		curnitRef.setAttribute("id", "curnit" + curnit_index);
339 		curnitRef.setAttribute("uuid", curnit.getCurnitId().toString());
340 		authorData.appendChild(curnitRef);
341 
342 		Collection<?> referencedPods = curnit.getReferencedPods();
343 		for (Object name : referencedPods) {
344 			Pod pod = (Pod) name;
345 			Element podRef = doc.createElement("podRef");
346 			int pod_index = indexOf(pod);
347 			podRef.setAttribute("id", "pod" + pod_index);
348 			podRef.setAttribute("uuid", pod.getPodId().toString());
349 			authorData.appendChild(podRef);
350 		}
351 
352 		return authorData;
353 	}
354 
355 	/**
356 	 * @param podId
357 	 * @return
358 	 */
359 	private int indexOf(Pod pod) {
360 		int index = pods.indexOf(pod);
361 		if (index == -1) {
362 			// add it
363 			index = pods.size();
364 			pods.add(pod);
365 		}
366 		return index;
367 	}
368 
369 	/**
370 	 * @param curnit
371 	 * @return
372 	 */
373 	private int indexOf(Curnit curnit) {
374 		int index = curnits.indexOf(curnit);
375 		if (index == -1) {
376 			// add it
377 			index = curnits.size();
378 			curnits.add(curnit);
379 		}
380 		return index;
381 	}
382 
383 	static List<Curnit> curnits = new ArrayList<Curnit>();
384 
385 	static List<Pod> pods = new ArrayList<Pod>();
386 
387 	/* (non-Javadoc)
388 	 * @see net.sf.sail.core.entity.AgentFactory#createAgent(net.sf.sail.core.entity.Role)
389 	 */
390 	public IAgent createAgent(Role role) {
391 		MemoryAgent agent = new MemoryAgent(role);
392 		addAgent(agent);
393 		return agent;
394 	};
395 
396 }