001: /* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved.
002: * This code is licensed under the GPL 2.0 license, availible at the root
003: * application directory.
004: */
005: package org.vfny.geoserver.global;
006:
007: import org.apache.struts.action.ActionServlet;
008: import org.apache.struts.action.PlugIn;
009: import org.apache.struts.config.ModuleConfig;
010: import org.geotools.validation.dto.PlugInDTO;
011: import org.geotools.validation.dto.TestDTO;
012: import org.geotools.validation.dto.TestSuiteDTO;
013: import org.springframework.beans.factory.InitializingBean;
014: import org.vfny.geoserver.global.xml.XMLConfigWriter.WriterUtils;
015: import java.io.File;
016: import java.util.Date;
017: import java.util.HashMap;
018: import java.util.Iterator;
019: import java.util.LinkedList;
020: import java.util.List;
021: import java.util.Map;
022: import javax.servlet.ServletException;
023:
024: /**
025: * This class represents the state of the GeoServer appliaction.
026: *
027: * <p>
028: * ApplicationState used by the state.jsp tile as a single view on the state of
029: * the GeoServer application. This class may be extended in the future to
030: * provide runtime statistics.
031: * </p>
032: *
033: * <p>
034: * This class is not a bean - content is updated based on methods. As an
035: * example consider the following State diagram:
036: * </p>
037: *
038: * @author dzwiers, Refractions Research, Inc.
039: * @version $Id: ApplicationState.java 7579 2007-10-09 22:30:14Z jdeolive $
040: */
041: public class ApplicationState implements PlugIn, InitializingBean {
042: /** The key used to store this value in the Web Container */
043: public static final String WEB_CONTAINER_KEY = "GeoServer.ApplicationState";
044:
045: /** Non null if configuration has been edited (but not applied) */
046: private Date configTimestamp;
047:
048: /** Non null if the geoserver setup has been changed (but not saved) */
049: private Date appTimestamp;
050:
051: /** Non null if the modification date of the xml files is known */
052: private Date xmlTimestamp;
053:
054: /** magic, be very careful with this array. defined below in loadStatus() */
055: private int[] geoserverStatus = new int[13];
056: private Map geoserverNSErrors;
057: private Map geoserverDSErrors;
058: private Map geoserverVPErrors;
059:
060: /**
061: * Data module
062: */
063: Data data;
064:
065: /**
066: * Validation module
067: */
068: GeoValidator validator;
069:
070: /**
071: * Configuration module
072: */
073: Config config;
074:
075: /**
076: *
077: * @deprecated use {@link #ApplicationState(Data, GeoValidator, Config)}
078: */
079: public ApplicationState() {
080: this (null, null, null);
081: }
082:
083: /**
084: * Creates a new appliction state.
085: *
086: * @param data The data modle.
087: * @param validator The validation module
088: */
089: public ApplicationState(Data data, GeoValidator validator,
090: Config config) {
091: this .data = data;
092: this .validator = validator;
093: this .config = config;
094: }
095:
096: /**
097: * Clean up the Configuration State during application exit.
098: *
099: * <p>
100: * Since this class just holds data, no resources need to be released.
101: * </p>
102: *
103: * @see org.apache.struts.action.PlugIn#destroy()
104: */
105: public void destroy() {
106: }
107:
108: /**
109: * Set up the ApplicationState during Application start up.
110: *
111: * <p>
112: * ApplicationState simply registers itself with the WEB_CONTAINER_KEY
113: * ("GeoServer.ApplicationState") during start up.
114: * </p>
115: *
116: * @param actionServlet ActionServlet representing the Application
117: * @param moduleConfig Configuration used to set up this plug in
118: *
119: * @throws ServletException
120: *
121: * @see org.apache.struts.action.PlugIn#init(org.apache.struts.action.ActionServlet,
122: * org.apache.struts.config.ModuleConfig)
123: *
124: * @deprecated This class is no longer loaded with struts,
125: * use {@link #afterPropertiesSet()}
126: */
127: public void init(ActionServlet actionServlet,
128: ModuleConfig moduleConfig) throws ServletException {
129: try {
130: afterPropertiesSet();
131: } catch (Exception e) {
132: throw new ServletException(e);
133: }
134: }
135:
136: public void afterPropertiesSet() throws Exception {
137: configTimestamp = getXmlTimestamp();
138: appTimestamp = configTimestamp;
139:
140: geoserverStatus[0] = -1;
141: }
142:
143: /**
144: * True if the user has changed the Configuration and not yet applied them.
145: *
146: * @return <code>true</code> if Configuration needs changing.
147: */
148: public boolean isConfigChanged() {
149: return (configTimestamp != null)
150: && ((appTimestamp == null) || configTimestamp
151: .after(appTimestamp));
152: }
153:
154: /** Validation is part of the Configuration Process */
155: private boolean isValidationChanged() {
156: return isConfigChanged();
157: }
158:
159: /**
160: * True if the user has changed GeoServer and not yet saved the changes.
161: *
162: * @return <code>true</code> if GeoServer has been changed (but not saved)
163: */
164: public boolean isAppChanged() {
165: return (appTimestamp != null)
166: && appTimestamp.after(getXmlTimestamp());
167: }
168:
169: /**
170: * Notification that Config has been updated from XML config files
171: */
172: public void notifyLoadXML() {
173: // Correct, this represents a load into config from xml
174: appTimestamp = xmlTimestamp;
175: configTimestamp = xmlTimestamp;
176: }
177:
178: /**
179: * Notification that Global has been updated from Configuration
180: */
181: public void notifyToGeoServer() {
182: appTimestamp = new Date();
183: }
184:
185: /**
186: * Notification that Global has been saved to XML config files.
187: */
188: public void notifiySaveXML() {
189: xmlTimestamp = new Date();
190: }
191:
192: /**
193: * Notification that the User has changed the Configuration
194: */
195: public void notifyConfigChanged() {
196: configTimestamp = new Date();
197: }
198:
199: /**
200: * signal to any listeners that config has changed.
201: */
202: public void fireChange() {
203: data.getGeoServer().fireChange();
204: }
205:
206: /** Q: what is this supposed to do? */
207: public int getWcsGood() {
208: if (geoserverStatus[0] != ((isAppChanged() ? 1 : 0)
209: + (isConfigChanged() ? 2 : 0) + (isValidationChanged() ? 4
210: : 0))) {
211: loadStatus();
212: }
213:
214: return geoserverStatus[4];
215: }
216:
217: /** q: What foul manner of magic is this? */
218: public int getWcsBad() {
219: if (geoserverStatus[0] != ((isAppChanged() ? 1 : 0)
220: + (isConfigChanged() ? 2 : 0) + (isValidationChanged() ? 4
221: : 0))) {
222: loadStatus();
223: }
224:
225: return geoserverStatus[5];
226: }
227:
228: /** q: This does not make a lot of sense - did you want to consult both ConfigChanged and GeoServer changed? */
229: public int getWcsDisabled() {
230: if (geoserverStatus[0] != ((isAppChanged() ? 1 : 0)
231: + (isConfigChanged() ? 2 : 0) + (isValidationChanged() ? 4
232: : 0))) {
233: loadStatus();
234: }
235:
236: return geoserverStatus[6];
237: }
238:
239: /** Q: what is this supposed to do? */
240: public int getWfsGood() {
241: if (geoserverStatus[0] != ((isAppChanged() ? 1 : 0)
242: + (isConfigChanged() ? 2 : 0) + (isValidationChanged() ? 4
243: : 0))) {
244: loadStatus();
245: }
246:
247: return geoserverStatus[1];
248: }
249:
250: /** q: What foul manner of magic is this? */
251: public int getWfsBad() {
252: if (geoserverStatus[0] != ((isAppChanged() ? 1 : 0)
253: + (isConfigChanged() ? 2 : 0) + (isValidationChanged() ? 4
254: : 0))) {
255: loadStatus();
256: }
257:
258: return geoserverStatus[2];
259: }
260:
261: /** q: This does not make a lot of sense - did you want to consult both ConfigChanged and GeoServer changed? */
262: public int getWfsDisabled() {
263: if (geoserverStatus[0] != ((isAppChanged() ? 1 : 0)
264: + (isConfigChanged() ? 2 : 0) + (isValidationChanged() ? 4
265: : 0))) {
266: loadStatus();
267: }
268:
269: return geoserverStatus[3];
270: }
271:
272: /** Q: scary magic */
273: public int getWmsGood() {
274: if (geoserverStatus[0] != ((isAppChanged() ? 1 : 0)
275: + (isConfigChanged() ? 2 : 0) + (isValidationChanged() ? 4
276: : 0))) {
277: loadStatus();
278: }
279:
280: return geoserverStatus[4];
281: }
282:
283: /** Q: scary magic */
284: public int getWmsBad() {
285: if (geoserverStatus[0] != ((isAppChanged() ? 1 : 0)
286: + (isConfigChanged() ? 2 : 0) + (isValidationChanged() ? 4
287: : 0))) {
288: loadStatus();
289: }
290:
291: return geoserverStatus[5];
292: }
293:
294: /** Q: scary magic */
295: public int getWmsDisabled() {
296: if (geoserverStatus[0] != ((isAppChanged() ? 1 : 0)
297: + (isConfigChanged() ? 2 : 0) + (isValidationChanged() ? 4
298: : 0))) {
299: loadStatus();
300: }
301:
302: return geoserverStatus[6];
303: }
304:
305: public int getDataGood() {
306: if (geoserverStatus[0] != ((isAppChanged() ? 1 : 0)
307: + (isConfigChanged() ? 2 : 0) + (isValidationChanged() ? 4
308: : 0))) {
309: loadStatus();
310: }
311:
312: return geoserverStatus[7];
313: }
314:
315: public int getDataBad() {
316: if (geoserverStatus[0] != ((isAppChanged() ? 1 : 0)
317: + (isConfigChanged() ? 2 : 0) + (isValidationChanged() ? 4
318: : 0))) {
319: loadStatus();
320: }
321:
322: return geoserverStatus[8];
323: }
324:
325: public int getDataDisabled() {
326: if (geoserverStatus[0] != ((isAppChanged() ? 1 : 0)
327: + (isConfigChanged() ? 2 : 0) + (isValidationChanged() ? 4
328: : 0))) {
329: loadStatus();
330: }
331:
332: return geoserverStatus[9];
333: }
334:
335: public int getGeoserverGood() {
336: if (geoserverStatus[0] != ((isAppChanged() ? 1 : 0)
337: + (isConfigChanged() ? 2 : 0) + (isValidationChanged() ? 4
338: : 0))) {
339: loadStatus();
340: }
341:
342: return (int) ((geoserverStatus[1] + geoserverStatus[4] + geoserverStatus[7]) / 3.0);
343: }
344:
345: public int getGeoserverBad() {
346: if (geoserverStatus[0] != ((isAppChanged() ? 1 : 0)
347: + (isConfigChanged() ? 2 : 0) + (isValidationChanged() ? 4
348: : 0))) {
349: loadStatus();
350: }
351:
352: return (int) ((geoserverStatus[2] + geoserverStatus[5] + geoserverStatus[8]) / 3.0);
353: }
354:
355: public int getGeoserverDisabled() {
356: if (geoserverStatus[0] != ((isAppChanged() ? 1 : 0)
357: + (isConfigChanged() ? 2 : 0) + (isValidationChanged() ? 4
358: : 0))) {
359: loadStatus();
360: }
361:
362: return (int) ((geoserverStatus[3] + geoserverStatus[6] + geoserverStatus[9]) / 3.0);
363: }
364:
365: /**
366: *
367: * loadStatus purpose.
368: * <p>
369: * Magic occurs here, so be careful. This sets the values in the geoserverStatus array.
370: * </p>
371: * <p>
372: * The array is broken into four blocks, [0],[1-3],[4-6],[7-9].
373: * <ul>
374: * <li>[0] - The first block represtents the application state at the time
375: * of data creation. Use to test whether the array needs to be
376: * reloaded.</li>
377: * <li>[1-3] - wfs (working, broken, disabled) percentages</li>
378: * <li>[4-6] - wms (working, broken, disabled) percentages</li>
379: * <li>[7-9] - data (working, broken, disabled) percentages</li>
380: * </ul>
381: * </p>
382: */
383: private void loadStatus() {
384: // what does isGeoServerChanged() have to do with this
385: // and why don't you use (isGeoServerChanged() ? 3 : 0)
386: //
387: // or are you trying to indicate a bit mask:
388: // bit 1: isGeoServerChanged
389: // bit 2: isConfigChanged
390: //
391: // And all this madness is a cut and paste mistake?
392: geoserverStatus[0] = (isAppChanged() ? 1 : 0)
393: + (isConfigChanged() ? 2 : 0)
394: + (isValidationChanged() ? 4 : 0);
395:
396: // setup geoserverNSErrors
397: geoserverNSErrors = data.statusNamespaces();
398:
399: // setup geoserverDSErrors
400: geoserverDSErrors = data.statusDataStores();
401:
402: // setup geoserverVPErrors
403: Map tmpVP = validator.getErrors();
404:
405: int g = 0;
406: int b = 0;
407: int d = 0;
408: Iterator i = null;
409:
410: //featuretypes
411: i = geoserverNSErrors.keySet().iterator();
412:
413: while (i.hasNext()) {
414: Object key = i.next();
415: Object o = geoserverNSErrors.get(key);
416:
417: if (o.equals(Boolean.TRUE)) {
418: g++;
419: i.remove();
420:
421: //geoserverNSErrors.remove(key);
422: } else {
423: if (o.equals(Boolean.FALSE)) {
424: d++;
425: i.remove();
426:
427: //geoserverNSErrors.remove(key);
428: } else {
429: b++;
430: }
431: }
432: }
433:
434: if ((g + b + d) == 0) {
435: geoserverStatus[7] = 100;
436: geoserverStatus[8] = 0;
437: geoserverStatus[9] = 0;
438: } else {
439: geoserverStatus[7] = (int) ((100.0 * g) / (g + b + d));
440: geoserverStatus[8] = (int) ((100.0 * b) / (g + b + d));
441: geoserverStatus[9] = (int) ((100.0 * d) / (g + b + d));
442: }
443:
444: //datastores
445: i = geoserverDSErrors.keySet().iterator();
446: g = 0;
447: b = 0;
448: d = 0;
449:
450: while (i.hasNext()) {
451: Object key = i.next();
452: Object o = geoserverDSErrors.get(key);
453:
454: if (o.equals(Boolean.TRUE)) {
455: g++;
456: i.remove();
457:
458: //geoserverDSErrors.remove(key);
459: } else {
460: if (o.equals(Boolean.FALSE)) {
461: d++;
462: i.remove();
463:
464: //geoserverDSErrors.remove(key);
465: } else {
466: b++;
467: }
468: }
469: }
470:
471: if ((g + b + d) == 0) {
472: geoserverStatus[1] = geoserverStatus[4] = 100;
473: geoserverStatus[2] = geoserverStatus[5] = 0;
474: geoserverStatus[3] = geoserverStatus[6] = 0;
475: } else {
476: geoserverStatus[1] = geoserverStatus[4] = (int) ((100.0 * g) / (g
477: + b + d));
478: geoserverStatus[2] = geoserverStatus[5] = (int) ((100.0 * b) / (g
479: + b + d));
480: geoserverStatus[3] = geoserverStatus[6] = (int) ((100.0 * d) / (g
481: + b + d));
482: }
483:
484: //validation
485: // DJB: noticed that you can have no loaded validation plugins, so this can be null)
486: g = 0;
487: b = 0;
488: d = 0;
489:
490: if (tmpVP != null) {
491: i = tmpVP.keySet().iterator();
492:
493: while (i.hasNext()) {
494: Object key = i.next();
495: Object o = tmpVP.get(key);
496:
497: if (o.equals(Boolean.TRUE)) {
498: g++;
499: i.remove();
500:
501: //geoserverDSErrors.remove(key);
502: } else {
503: if (o.equals(Boolean.FALSE)) {
504: d++;
505: i.remove();
506:
507: //geoserverDSErrors.remove(key);
508: } else {
509: b++;
510: }
511: }
512: }
513: }
514:
515: if ((g + b + d) == 0) {
516: geoserverStatus[10] = 100;
517: geoserverStatus[11] = 0;
518: geoserverStatus[12] = 0;
519: } else {
520: geoserverStatus[10] = (int) ((100.0 * g) / (g + b + d));
521: geoserverStatus[11] = (int) ((100.0 * b) / (g + b + d));
522: geoserverStatus[12] = (int) ((100.0 * d) / (g + b + d));
523: }
524:
525: geoserverVPErrors = new HashMap();
526:
527: if (tmpVP != null) //DJB: protection for no validation services
528: {
529: i = tmpVP.entrySet().iterator();
530:
531: while (i.hasNext()) {
532: Map.Entry e = (Map.Entry) i.next();
533: Object dto = e.getKey();
534:
535: if (dto instanceof PlugInDTO) {
536: geoserverVPErrors
537: .put("PlugIn:"
538: + ((PlugInDTO) dto).getName(), e
539: .getValue());
540: } else {
541: if (dto instanceof TestDTO) {
542: geoserverVPErrors.put("Test:"
543: + ((TestDTO) dto).getName(), e
544: .getValue());
545: } else {
546: if (dto instanceof TestSuiteDTO) {
547: geoserverVPErrors.put("TestSuite:"
548: + ((TestSuiteDTO) dto).getName(), e
549: .getValue());
550: }
551: }
552: }
553: }
554: }
555: }
556:
557: public Exception getDataStoreError(String key) {
558: return (Exception) getDataStoreErrors().get(key);
559: }
560:
561: public Exception getNameSpaceError(String key) {
562: return (Exception) getNameSpaceErrors().get(key);
563: }
564:
565: public Exception getWFSError(String key) {
566: return (Exception) getNameSpaceErrors().get(key);
567: }
568:
569: public Exception getWMSError(String key) {
570: return (Exception) getNameSpaceErrors().get(key);
571: }
572:
573: public Exception getValidationError(String key) {
574: return (Exception) getValidationErrors().get(key);
575: }
576:
577: /**
578: * Namespace Exceptions by prefix:typeName.
579: * <p>
580: * This only includes problems! If this map is null or isEmpty
581: * status is "ready".
582: * </p>
583: * @return
584: */
585: public Map getNameSpaceErrors() {
586: if ((geoserverNSErrors == null)
587: || (geoserverStatus[0] == ((isAppChanged() ? 1 : 0)
588: + (isConfigChanged() ? 2 : 0) + (isValidationChanged() ? 4
589: : 0)))) {
590: loadStatus();
591: }
592:
593: return geoserverNSErrors;
594: }
595:
596: /** Flattened for your JSP pleasure */
597: public List getNameSpaceErrorKeys() {
598: return new LinkedList(getNameSpaceErrors().keySet());
599: }
600:
601: /** Flattened for your JSP pleasure */
602: public List getNameSpaceErrorValues() {
603: return new LinkedList(getNameSpaceErrors().values());
604: }
605:
606: /**
607: * DataStore Exceptions by dataStoreId:typeName
608: * <p>
609: * This only includes problems! If this map is null or isEmpty
610: * status is "ready".
611: * </p>
612: * @return
613: */
614: public Map getDataStoreErrors() {
615: if ((geoserverDSErrors == null)
616: || (geoserverStatus[0] == ((isConfigChanged() ? 1 : 0)
617: + (isAppChanged() ? 2 : 0) + (isValidationChanged() ? 4
618: : 0)))) {
619: loadStatus();
620: }
621:
622: return geoserverDSErrors;
623: }
624:
625: /** Flattened for your JSP pleasure */
626: public List getDataStoreErrorKeys() {
627: return new LinkedList(getDataStoreErrors().keySet());
628: }
629:
630: /** Flattened for your JSP pleasure */
631: public List getDataStoreErrorValues() {
632: return new LinkedList(getDataStoreErrors().values());
633: }
634:
635: /**
636: * Validation Exceptions by obejct type : name where object type is one of TestSuite, Test, PlugIn
637: * <p>
638: * This only includes problems! If this map is null or isEmpty
639: * status is "ready".
640: * </p>
641: * @return
642: */
643: public Map getValidationErrors() {
644: if ((geoserverNSErrors == null)
645: || (geoserverStatus[0] == ((isAppChanged() ? 1 : 0)
646: + (isConfigChanged() ? 2 : 0) + (isValidationChanged() ? 4
647: : 0)))) {
648: loadStatus();
649: }
650:
651: return geoserverVPErrors;
652: }
653:
654: /** Flattened for your JSP pleasure */
655: public List getValidationErrorKeys() {
656: return new LinkedList(getValidationErrors().keySet());
657: }
658:
659: /** Flattened for your JSP pleasure */
660: public List getValidationErrorValues() {
661: return new LinkedList(getValidationErrors().values());
662: }
663:
664: public Map getWCSErrors() {
665: return getNameSpaceErrors();
666: }
667:
668: public List getWCSErrorKeys() {
669: return getNameSpaceErrorKeys();
670: }
671:
672: public Map getWFSErrors() {
673: return getNameSpaceErrors();
674: }
675:
676: public List getWFSErrorKeys() {
677: return getNameSpaceErrorKeys();
678: }
679:
680: public Map getWMSErrors() {
681: return getNameSpaceErrors();
682: }
683:
684: public List getWMSErrorKeys() {
685: return getNameSpaceErrorKeys();
686: }
687:
688: /**
689: * Access appTimestamp property.
690: *
691: * @return Returns the appTimestamp.
692: */
693: public Date getAppTimestamp() {
694: return appTimestamp;
695: }
696:
697: /**
698: * Access configTimestamp property.
699: *
700: * @return Returns the configTimestamp.
701: */
702: public Date getConfigTimestamp() {
703: return configTimestamp;
704: }
705:
706: /**
707: * Access xmlTimestamp property.
708: *
709: * @return Returns the xmlTimestamp.
710: */
711: public Date getXmlTimestamp() {
712: if (xmlTimestamp == null) {
713: //DJB: changed for geoserver_data_dir
714: File dataDir = config.dataDirectory();
715: boolean inDataDir = GeoserverDataDirectory.isTrueDataDir();
716:
717: //We're just checking if it's actually a data_dir, not trying to
718: //to do backwards compatibility. So if an old data_dir is made in
719: //the old way, on save it'll come to the new way. -ch
720: File serviceDir = dataDir;
721: File serviceFile;
722:
723: try {
724: serviceFile = WriterUtils.initWriteFile(new File(
725: serviceDir, "services.xml"), false);
726: } catch (ConfigurationException confE) {
727: throw new RuntimeException(confE);
728: }
729:
730: xmlTimestamp = new Date(serviceFile.lastModified());
731: }
732:
733: return xmlTimestamp;
734: }
735:
736: private void resetXMLTimestamp() {
737: xmlTimestamp = null;
738: }
739: }
|