ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/cms/source/server/uk/org/iscream/cms/server/componentmanager/XMLCache.java
Revision: 1.1
Committed: Sat Oct 12 21:52:00 2002 UTC (21 years, 7 months ago) by tdb
Branch: MAIN
Log Message:
Addition of an XMLCache class. This class tries to help cut down on the
number of times we parse a single piece of XML. Using this class will
ensure that a String of XML is only decoded once within a given JVM. This
has been shown to be significantly more efficient than parsing it multiple
times in tests.
Next step is to integrate this into the rest of the server.
I'd also like to investigate tweaking the initial size and loading factor
of the HashMaps used within this class.

File Contents

# Content
1 /*
2 * i-scream central monitoring system
3 * http://www.i-scream.org.uk
4 * Copyright (C) 2000-2002 i-scream
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21 //---PACKAGE DECLARATION---
22 package uk.org.iscream.cms.server.componentmanager;
23
24 //---IMPORTS---
25 import java.util.HashMap;
26 import uk.org.iscream.cms.server.util.*;
27 import uk.org.iscream.cms.server.core.*;
28
29 /**
30 * An XMLCache to cut down the cost of XML parsing.
31 * This class tries to ensure we only parse a String of XML
32 * into an XML packet once.
33 *
34 * @author $Author$
35 * @version $Id$
36 */
37 class XMLCache extends Thread {
38
39 //---FINAL ATTRIBUTES---
40
41 /**
42 * The current CVS revision of this class
43 */
44 public static final String REVISION = "$Revision$";
45
46 /**
47 * The default period for cleaning out old XMLPackets
48 */
49 public final int DEFAULT_CLEANUP_PERIOD = 30;
50
51 //---STATIC METHODS---
52
53 /**
54 * Reference to our instance - we're a singleton.
55 */
56 private static XMLCache _instance;
57
58 /**
59 * Static initialiser block for constructing the initial
60 * instance of this singleton.
61 */
62 static {
63 _instance = new XMLCache();
64 }
65
66 /**
67 * Return a reference to our singleton.
68 */
69 public static XMLCache getInstance() {
70 return _instance;
71 }
72
73 //---CONSTRUCTORS---
74
75 /**
76 * A private constructor to start this class up
77 */
78 private XMLCache() {
79 // set the Thread name
80 setName("componentmanager.XMLCache");
81 // and start it
82 start();
83 }
84
85 //---PUBLIC METHODS---
86
87 /**
88 * Main loop for the thread to clean out old XMLPackets. This is
89 * done by swapping HashMap's around. This seemed like the most
90 * efficient approach, and is infact a documented garbage collection
91 * technique :)
92 */
93 public void run() {
94 while(_running) {
95 // get cleanup period from configuration
96 int cleanupPeriod = 0;
97 try {
98 cleanupPeriod = Integer.parseInt(ConfigurationProxy.getInstance().getProperty("XMLCache", "XMLCache.cleanupPeriod"));
99 } catch (NumberFormatException e) {
100 cleanupPeriod = DEFAULT_CLEANUP_PERIOD;
101 _logger.write(toString(), Logger.WARNING, "Erronous XMLCache.cleanupPeriod value in configuration using default of " + cleanupPeriod + " seconds");
102 } catch (PropertyNotFoundException e) {
103 cleanupPeriod = DEFAULT_CLEANUP_PERIOD;
104 _logger.write(toString(), Logger.WARNING, "XMLCache.cleanupPeriod value unavailable using default of " + cleanupPeriod + " seconds");
105 }
106
107 // wait for determined length of time
108 try {
109 Thread.sleep(cleanupPeriod * 1000);
110 } catch (InterruptedException e) {
111 }
112
113 // do the swap
114 synchronized (this) {
115 _hashB = _hashA;
116 // creating a new HashMap is quicker than clearing the old one
117 _hashA = new HashMap();
118 }
119 }
120 }
121
122 /**
123 * Overrides the {@link java.lang.Object#toString() Object.toString()}
124 * method to provide clean logging (every class should have this).
125 *
126 * This uses the uk.org.iscream.cms.server.util.FormatName class
127 * to format the toString()
128 *
129 * @return the name of this class and its CVS revision
130 */
131 public String toString() {
132 return FormatName.getName(
133 _name,
134 getClass().getName(),
135 REVISION);
136 }
137
138 //---PRIVATE METHODS---
139
140 //---ACCESSOR/MUTATOR METHODS---
141
142 /**
143 * Generates an XMLPacket from a given String of XML, checking
144 * to see if it already has the XMLPacket cached.
145 *
146 * @param xml A String of XML data
147 * @return An XMLPacket representing the xml parameter
148 * @throws InvalidXMLException if the XML does not parse
149 */
150 public XMLPacket getXMLPacket(String xml) throws InvalidXMLException {
151 // Hash A is more likely to contain the result, assuming we have our
152 // swap timing about right :)
153 if(_hashA.containsKey(xml)) {
154 return (XMLPacket) _hashA.get(xml);
155 }
156 else if(_hashB.containsKey(xml)) {
157 return (XMLPacket) _hashB.get(xml);
158 }
159 else {
160 XMLPacket packet = _xmlPacketMaker.createXMLPacket(xml);
161 // always add to hash A
162 _hashA.put(xml, packet);
163 return packet;
164 }
165 }
166
167 //---ATTRIBUTES---
168
169 // think about initial parameters for HashMap's
170
171 /**
172 * Our primary HashMap
173 */
174 private HashMap _hashA = new HashMap();
175
176 /**
177 * Our secondary HashMap
178 */
179 private HashMap _hashB = new HashMap();
180
181 /**
182 * A reference to an XMLPacketMaker which we can use
183 * to generate XMLPackets from XML Strings
184 */
185 private XMLPacketMaker _xmlPacketMaker = new XMLPacketMaker();
186
187 /**
188 * We can set this to false to stop the Thread
189 */
190 private boolean _running = true;
191
192 /**
193 * This is the friendly identifier of the
194 * component this class is running in.
195 * eg, a Filter may be called "filter1",
196 * If this class does not have an owning
197 * component, a name from the configuration
198 * can be placed here. This name could also
199 * be changed to null for utility classes.
200 */
201 private String _name = null;
202
203 /**
204 * This holds a reference to the
205 * system logger that is being used.
206 */
207 private Logger _logger = ReferenceManager.getInstance().getLogger();
208
209 //---STATIC ATTRIBUTES---
210
211 }