1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2001 by Sun Microsystems, Inc.
23  * All rights reserved.
24  *
25  * DataModel.java
26  */
27 
28 package com.sun.wbem.solarisprovider.srm;
29 
30 import java.util.HashMap;
31 import java.util.Vector;
32 import java.util.Iterator;
33 
34 
35 /**
36  * Aggregation of all users, projects, and sets metrics data.
37  * Implements the singleton pattern
38  * @author Sun Microsystems, Inc.
39  */
40 class DataModel {
41 
42     private static DataModel		dm;
43     private static SRMDataReader	dr;
44     private static boolean		doAlive;
45     /**
46      * syncObject guards the calls of SRMDataReader methods between the
47      * current data model thread and the KeepAlive thread.
48      */
49     private static Object		syncObject;
50     /**
51      * rdsKeepAliveTimeout: how long the KeepAlive thread should keep
52      * the connection opened.
53      */
54     private static int rdsKeepAliveTimeout = 30 * 60000;
55     private static KeepAlive	ka;
56     private static boolean	kaError;
57     private static boolean  	msacct = false;
58 
59     private static final int PROCESSESHASHSIZE = 500;
60     private static final int USERPROCSHASHSIZE = 200;
61     private static final int PROJPROCSHASHSIZE = 100;
62     private static final int USERSHASHSIZE = 200;
63     private static final int PROJSHASHSIZE = 100;
64     private static final int L_PRC_SI = 1;
65     private static final int L_USR_SI = 2;
66     private static final int L_PRJ_SI = 3;
67     private static final int L_AC_USR = 4;
68     private static final int L_AC_PRJ = 5;
69     private static final int L_SYSTEM = 6;
70     private static final int L_ALL  = 20;
71 
72     // RDS exec command
73     private static final String RDSPGM = "/usr/sadm/lib/wbem/rds";
74 
75     private static final int	TIMEOUTIDX  = 3;
76     private static final int	INTERVALIDX = 5;
77 
78     // RDS commands
79     private static final String CMD_GETALL	= "-pUuJjS";
80     private static final String CMD_GETPL	= "-p";
81     private static final String CMD_GETUL	= "-u";
82     private static final String CMD_GETAUL	= "-U";
83     private static final String CMD_GETJL	= "-j";
84     private static final String CMD_GETAJL	= "-J";
85     private static final String CMD_GETASL	= "-S";
86     private static final String CMD_ALIVE	= "alive";
87     private static final String CMD_EXIT	= "exit";
88 
89     private static boolean updating; // set if udpdateing is in progress
90     private static boolean running;  // set if the rds is running
91 
92     private int rdsTimeout;
93     private int rdsInterval;
94     private String rdsArgs[];
95     protected HashMap processes	= new HashMap(PROCESSESHASHSIZE);
96     protected HashMap users	= new HashMap(USERSHASHSIZE);
97     protected HashMap userprocs	= new HashMap(USERPROCSHASHSIZE);
98     protected HashMap projs	= new HashMap(PROJSHASHSIZE);
99     protected HashMap projprocs	= new HashMap(PROJPROCSHASHSIZE);
100     protected SystemDataModel sdm = new  SystemDataModel();
101 
102     /**
103      * Default constructor
104      */
DataModel()105     private DataModel() {
106     }
107 
108     /**
109      * Should be used to obtain the singleton instance of this class
110      * @return	the singleton instance of this class
111      */
getHandle(Object syncObj)112     static DataModel getHandle(Object syncObj) {
113 
114     	if (dm == null) {
115 	    dm = new DataModel();
116 	    dr = new SRMDataReader(dm);
117 	    syncObject = syncObj;
118 	    try {
119 	    	if (Util.propertyKEEPALIVETIMEOUT != null) {
120 	    	    rdsKeepAliveTimeout =
121 		    	Integer.parseInt(Util.propertyKEEPALIVETIMEOUT);
122 	    	}
123 	    	if (Util.propertyMSACCT != null) {
124 	    	    msacct = Util.propertyMSACCT.equalsIgnoreCase("true");
125 	    	}
126 	    } catch (Exception e) { };
127     	}
128 	return dm;
129     }
130 
131     /**
132      * Initialize the rds timeouts, the actually opening is deleted
133      * until the first update call.
134      */
open(int rdsTimeout, int rdsInterval)135     void open(int rdsTimeout, int rdsInterval) {
136     	Vector args  = new Vector(6);
137     	String dbfile = null;
138 
139 	this.rdsTimeout = rdsTimeout;
140 	this.rdsInterval = rdsInterval;
141     	args.add(RDSPGM);
142     	args.add("-a");
143     	args.add("-t");
144     	args.add(""+rdsTimeout);
145     	args.add("-i");
146     	args.add(""+rdsInterval);
147 	if (Util.propertyRDSDATABASE != null) {
148     	    args.add("-f");
149     	    args.add(Util.propertyRDSDATABASE);
150 	}
151     	if (Util.propertyMSACCT != null &&
152 	    Util.propertyMSACCT.equalsIgnoreCase("true")) {
153     	    args.add("-m");
154 	}
155 	if (Util.propertyRDSLOGFILE != null) {
156     	    args.add("-L");
157     	    args.add(Util.propertyRDSLOGFILE);
158 	}
159 	rdsArgs = new String[args.size()];
160 	args.toArray(rdsArgs);
161 
162     } // end open
163 
164     /**
165      * Close the rds communication pipe.
166      */
close()167     void close() {
168 
169 	if (running) {
170 	    doAlive = false;
171 	    ka.interrupt();
172     	    synchronized (syncObject) {
173 	    	/*
174 		 * check again, since AliveThread could already close RDS
175 		 * when this thread was waiting on syncObject
176 		 */
177 	    	if (running) {
178 		    dr.closeRDS();
179 		    running = false;
180 		}
181 	    }
182 	}
183 
184     } // end close
185 
186     /**
187      * Close the rds communication pipe after an error has raised. In this
188      * case the rds will be shutdown instead of gently closed.
189      */
closeONError()190     void closeONError() {
191 	doAlive = false;
192     	ka.interrupt();
193     	dr.shutdownRDS();
194     	running = false;
195     }
196 
197     /**
198      * Get a provider data model object identified by id from the list defined
199      * by listt.
200      * @return	the provider data model object or null if other the  list type
201      *		or the provider object id are unsupported.
202      */
getProviderDataModel(int listt, String id)203     SRMProviderDataModel getProviderDataModel(int listt, String id) {
204 
205 	try {
206 	    switch (listt) {
207 		case  L_PRC_SI : return getProcess(Integer.parseInt(id));
208 		case  L_USR_SI : return getUserprocs(id);
209 		case  L_PRJ_SI : return getProjprocs(id);
210 		case  L_AC_USR : return getUser(id);
211 		case  L_AC_PRJ : return getProject(id);
212 		case  L_SYSTEM : return sdm;
213 		default: return null;
214 	    }
215 	} catch (NumberFormatException e) {
216 	    return null;
217 	}
218     }
219 
220     /**
221      * Get process metrics object.
222      * @param	pid the process id
223      * @return	metrics object with process metrics or new empty
224      *		object at first call.
225      */
getProcess(int pid)226     ProcessDataModel getProcess(int pid) {
227 
228 	ProcessDataModel pdm = null;
229 	Integer pidI = new Integer(pid);
230 
231 	if ((pdm = (ProcessDataModel) processes.get(pidI)) == null) {
232 	    if (updating == false)
233 	    	return null;
234 	    pdm = new ProcessDataModel(pid);
235 	    processes.put(pidI, pdm);
236 	}
237 	if (updating == true)
238 	    pdm.setUpdated(true);
239 
240 	return pdm;
241     }
242 
243     /**
244      * Get user metrics object.
245      * @param	uid the user id
246      * @return	metrics object with process metrics or new empty object at
247      *		first call.
248      */
getUserprocs(String uidStr)249     UserProcessAggregateDataModel getUserprocs(String uidStr) {
250 
251 	UserProcessAggregateDataModel  padm = null;
252 
253 	if ((padm = (UserProcessAggregateDataModel)
254 		userprocs.get(uidStr)) == null) {
255 	    if (updating == false)
256 	    	return null;
257 	    padm = new UserProcessAggregateDataModel(uidStr);
258 	    userprocs.put(uidStr, padm);
259 	}
260 
261 	if (updating == true)
262 	    padm.setUpdated(true);
263 
264 	return padm;
265     }
266 
267     /**
268      * Get project metrics object.
269      * @return	metrics object with process metrics or new empty
270      *		object at first call.
271      */
getProjprocs(String name)272     ProjectProcessAggregateDataModel getProjprocs(String name) {
273 
274 	ProjectProcessAggregateDataModel  padm = null;
275 
276 	if ((padm = (ProjectProcessAggregateDataModel)
277 		projprocs.get(name)) == null) {
278 	    if (updating == false)
279 	    	return null;
280 	    padm = new ProjectProcessAggregateDataModel(name);
281 	    projprocs.put(name, padm);
282 	}
283 	if (updating == true)
284 	    padm.setUpdated(true);
285 
286 	return padm;
287     }
288 
289     /**
290      * Get active user object.
291      * @param	name the user id as string
292      * @return	active user object.
293      */
getUser(String name)294     ActiveUserModel getUser(String name) {
295 
296 	ActiveUserModel aum = null;
297 
298 	if ((aum = (ActiveUserModel) users.get(name)) == null) {
299 	    if (updating == false)
300 	    	return null;
301 	    aum = new ActiveUserModel(name);
302 	    users.put(name, aum);
303 	}
304 	if (updating == true)
305 	    aum.setUpdated(true);
306 
307 	return aum;
308     }
309 
310     /**
311      * Get active project object.
312      * @param	name the project
313      * @return	project object.
314      */
getProject(String name)315     ActiveProjectModel getProject(String name) {
316 
317 	ActiveProjectModel apm = null;
318 
319 	if ((apm = (ActiveProjectModel) projs.get(name)) == null) {
320 	    if (updating == false)
321 	    	return null;
322 	    apm = new ActiveProjectModel(name);
323 	    projs.put(name, apm);
324 	}
325 	if (updating == true)
326 	    apm.setUpdated(true);
327 
328 	return apm;
329     }
330 
331     /**
332      * Returns an iterator over the Processes.
333      * @return iterator
334      */
getProcessIterator()335     Iterator getProcessIterator() {
336 	return processes.values().iterator();
337     }
338 
339     /**
340      * Returns an iterator over the Users.
341      * @return iterator
342      */
getUserIterator()343     Iterator getUserIterator() {
344 	return users.values().iterator();
345     }
346 
347     /**
348      * Returns an iterator over the Projects.
349      * @return iterator
350      */
getProjectIterator()351     Iterator getProjectIterator() {
352 	return projs.values().iterator();
353     }
354 
355     /**
356      * Returns an iterator over the user process aggregation.
357      * @return iterator
358      */
getUserprocsIterator()359     Iterator getUserprocsIterator() {
360 	    return userprocs.values().iterator();
361     }
362 
363     /**
364      * Returns an iterator over the project process aggregation.
365      * @return iterator
366      */
getProjprocsIterator()367     Iterator getProjprocsIterator() {
368 	return projprocs.values().iterator();
369     }
370 
371     /**
372      * Update the metrics data.
373      * @exception SRMProtocolException
374      */
update()375     void  update() throws SRMProtocolException {
376 
377 	SRMProviderDataModel pdm;
378 	int tries = 2;
379 
380 	while (tries-- > 0) {
381 	    if (!running) {
382 		dr.startRDS(rdsArgs);
383 		running = true;
384 	    	ka = new KeepAlive(rdsKeepAliveTimeout);
385 		ka.start();
386 	    }
387 	    try {
388 		synchronized (syncObject) {
389 		    /* check if AliveThread has set error flag */
390 		    if (kaError) {
391 		    	closeONError();
392 			continue;
393 	    	    /*
394 		     * check if rds is still running, since AliveThread
395 		     * could already close RDS when this thread was waiting
396 		     * on syncObject
397 		     */
398 		    } else if (running) {
399     	    	    	updating = true;
400 		    	dr.getUpdate(CMD_GETALL);
401 		    } else {
402 		    	tries = 2;
403 		    	continue;
404 		    }
405 		}
406 		ka.resetTimeout();
407 		updating = false;
408 		tries = 0;
409 	    } catch (SRMProtocolException e) {
410 	    	SRMDebug.trace(SRMDebug.TRACE_ALL, e.getMessage());
411 	    	closeONError();
412 		if (tries == 0)
413 		    throw e;
414 	    }
415 	}
416 	cleanUp();
417 
418     } // end update
419 
420     /**
421      * Remove all dead processes, users or projects.
422      */
cleanUp()423     private void cleanUp() {
424 
425 	cleanUpList(processes);
426 	cleanUpList(users);
427 	cleanUpList(userprocs);
428 	cleanUpList(projs);
429 	cleanUpList(projprocs);
430     }
431 
432     /**
433      * Remove all elements that heven't been updated in last update.
434      */
cleanUpList(HashMap map)435     private void cleanUpList(HashMap map) {
436 	Iterator i;
437 	SRMProviderDataModel pdm;
438 
439 	for (i = map.values().iterator(); i.hasNext(); ) {
440 	    if (!((pdm = (SRMProviderDataModel) i.next()).isUpdated())) {
441 		i.remove();
442 	    } else {
443 		pdm.setUpdated(false);
444 	    }
445 	}
446     }
447 
448     /**
449      * This thread keeps the rds and the communication with it alive by
450      * sending the alive message to rds.
451      */
452     class KeepAlive extends Thread {
453     	int keepAliveTimeout, save;
454 
455     	/**
456      	 * Constructor
457      	 * @param timeout how long to run at all
458      	 */
KeepAlive(int timeout)459 	public KeepAlive(int timeout) {
460 	    super("KeepAlive");
461 	    kaError = false;
462 	    keepAliveTimeout = timeout;
463 	    save = keepAliveTimeout;
464 	}
465 
run()466 	synchronized public void run() {
467 	    int myTimeout = 0;
468 	    int waitTime = rdsTimeout / 2;
469 
470 	    doAlive = true;
471 
472 	    while (doAlive) {
473 	    	/*
474 		 * the keepAliveTimeout value is set in constructor and
475 		 * in the resetTimeout() method. If its value is reseted
476 		 * the internal timer myTimeout value will be wind up.
477 		 */
478 	    	if (keepAliveTimeout > 0) {
479 		    myTimeout = keepAliveTimeout;
480 		    keepAliveTimeout = 0;
481 		}
482 		try {
483     	    	    synchronized (syncObject) {
484 		    	/*
485 			 * this thread has gained the sync object, but it
486 			 * also should check the doAlive flag since
487 			 * the dataModel thread could already removed it
488 			 * because of a protocol error
489 			 */
490 		    	if (doAlive) {
491 		    	    myTimeout -= waitTime;
492     	    	    	    kaError = true;
493 		    	    if (myTimeout <= 0) {
494 		    	    	dr.closeRDS();
495 		    	    	running = false;
496 		    	    	return;
497 		    	    } else {
498 		    	    	dr.alive();
499 			    }
500 			    kaError = false;
501 			} else {
502 			    return;
503 			}
504 		    }
505 		    wait(waitTime);
506 		} catch (InterruptedException e) {
507 	    	    SRMDebug.trace(SRMDebug.TRACE_ALL, e.getMessage());
508 		    return;
509     	    	} catch (SRMProtocolException e) {
510 	    	    SRMDebug.trace(SRMDebug.TRACE_ALL, e.getMessage());
511 		    return;
512 		}
513 	    }
514 	}
515 
516     	/**
517      	 * Reset the absolute timeout
518      	 */
resetTimeout()519 	public void resetTimeout() {
520 	    keepAliveTimeout = save;
521 	}
522 
523     } // end class KeepAlive
524 
525 
526     class ProjectProcessAggregateDataModel extends ProcessAggregateDataModel {
ProjectProcessAggregateDataModel(String id)527 	public ProjectProcessAggregateDataModel(String id) {
528 	    super(id);
529 	}
530 
setCIMInstance(boolean newInstance)531 	protected void setCIMInstance(boolean newInstance) {
532 	    super.setCIMInstance(newInstance);
533 	    setStrProp(newInstance, CREATIONCLASSNAME,
534 	      SOLARIS_PROJECTPROCESSAGGREGATESTATISTICALINFORMATION);
535 	    setStrProp(newInstance, NAME, name);
536 	}
537     }
538 
539     class UserProcessAggregateDataModel extends ProcessAggregateDataModel {
UserProcessAggregateDataModel(String id)540 	public UserProcessAggregateDataModel(String id) {
541 	    super(id);
542 	}
543 
setCIMInstance(boolean newInstance)544 	protected void setCIMInstance(boolean newInstance) {
545 	    super.setCIMInstance(newInstance);
546 	    setStrProp(newInstance, CREATIONCLASSNAME,
547 	      SOLARIS_USERPROCESSAGGREGATESTATISTICALINFORMATION);
548 	    setStrProp(newInstance, NAME, name);
549 	}
550     }
551 
552 } // end class DataModel
553