001: //serverObjects.java
002: //-----------------------
003: //(C) by Michael Peter Christen; mc@anomic.de
004: //first published on http://www.anomic.de
005: //Frankfurt, Germany, 2004
006: //(C) changes by Bjoern 'fuchs' Krombholz
007: //
008: // $LastChangedDate: $
009: // $LastChangedRevision: $
010: // $LastChangedBy: $
011: //
012: //This program is free software; you can redistribute it and/or modify
013: //it under the terms of the GNU General Public License as published by
014: //the Free Software Foundation; either version 2 of the License, or
015: //(at your option) any later version.
016:
017: //This program is distributed in the hope that it will be useful,
018: //but WITHOUT ANY WARRANTY; without even the implied warranty of
019: //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
020: //GNU General Public License for more details.
021:
022: //You should have received a copy of the GNU General Public License
023: //along with this program; if not, write to the Free Software
024: //Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
025:
026: //Using this software in any meaning (reading, learning, copying, compiling,
027: //running) means that you agree that the Author(s) is (are) not responsible
028: //for cost, loss of data or any harm that may be caused directly or indirectly
029: //by usage of this softare or this documentation. The usage of this software
030: //is on your own risk. The installation and usage (starting/running) of this
031: //software may allow other people or application to access your computer and
032: //any attached devices and is highly dependent on the configuration of the
033: //software which must be done by the user of the software; the author(s) is
034: //(are) also not responsible for proper configuration and usage of the
035: //software, even if provoked by documentation provided together with
036: //the software.
037:
038: //Any changes to this file according to the GPL as documented in the file
039: //gpl.txt aside this file in the shipment you received can be done to the
040: //lines that follows this copyright notice here, but changes must not be
041: //done inside the copyright notive above. A re-distribution must contain
042: //the intact and unchanged copyright notice.
043: //Contributions and changes to the program code must be marked as such.
044:
045: /*
046: Why do we need this Class?
047: The purpose of this class is to provide a hashtable object to the server
048: and implementing interfaces. Values to and from cgi pages are encapsulated in
049: this object. The server shall be executable in a Java 1.0 environment,
050: so the following other options did not comply:
051:
052: Properties - setProperty would be needed, but only available in 1.2
053: HashMap, TreeMap - only in 1.2
054: Hashtable - available in 1.0, but 'put' does not accept null values
055:
056: So this class was created as a convenience.
057: It will also contain special methods that read data from internet-resources
058: in the background, while data can already be read out of the object.
059: This shall speed up usage when a slow internet connection is used (dial-up)
060: */
061:
062: package de.anomic.server;
063:
064: import java.io.BufferedOutputStream;
065: import java.io.File;
066: import java.io.FileOutputStream;
067: import java.io.IOException;
068: import java.io.UnsupportedEncodingException;
069: import java.net.InetAddress;
070: import java.util.ArrayList;
071: import java.util.HashMap;
072: import java.util.Iterator;
073: import java.util.Map;
074:
075: import de.anomic.data.htmlTools;
076: import de.anomic.plasma.plasmaSwitchboard;
077: import de.anomic.tools.yFormatter;
078:
079: public class serverObjects extends HashMap<String, String> implements
080: Cloneable {
081:
082: private static final long serialVersionUID = 1L;
083: private boolean localized = true;
084:
085: public serverObjects() {
086: super ();
087: }
088:
089: public serverObjects(int initialCapacity) {
090: super (initialCapacity);
091: }
092:
093: public serverObjects(Map<String, String> input) {
094: super (input);
095: }
096:
097: /**
098: * Add a key-value pair of Objects to the map.
099: * @param key This method will do nothing if the key is <code>null</code>.
100: * @param value The value that should be mapped to the key.
101: * If value is <code>null</code>, then the element at <code>key</code>
102: * is removed from the map.
103: * @return The value that was added to the map.
104: * @see java.util.Hashtable#put(K, V)
105: */
106: public String put(String key, String value) {
107: if (key == null) {
108: // this does nothing
109: return null;
110: } else if (value == null) {
111: // assigning the null value creates the same effect like removing the element
112: return super .remove(key);
113: } else {
114: return super .put(key, value);
115: }
116: }
117:
118: /**
119: * Add byte array to the map, value is kept as it is.
120: * @param key key name as String.
121: * @param value mapped value as a byte array.
122: * @return the previous value as String.
123: */
124: public String put(String key, byte[] value) {
125: return this .put(key, new String(value)); //TODO: do we need an encoding method for byte[]?
126: }
127:
128: /**
129: * Add an unformatted String representation of a double/float value
130: * to the map.
131: * @param key key name as String.
132: * @param value value as double/float.
133: * @return value as it was added to the map or <code>NaN</code> if an error occured.
134: */
135: public double put(String key, double value) {
136: if (null == this .put(key, Double.toString(value))) {
137: return Double.NaN;
138: } else {
139: return value;
140: }
141: }
142:
143: /**
144: * same as {@link #put(String, double)} but for integer types
145: * @return Returns 0 for the error case.
146: */
147: public long put(String key, long value) {
148: if (null == this .put(key, Long.toString(value))) {
149: return 0;
150: } else {
151: return value;
152: }
153: }
154:
155: public String put(String key, java.util.Date value) {
156: return this .put(key, value.toString());
157: }
158:
159: public String put(String key, serverDate value) {
160: return this .put(key, value.toString());
161: }
162:
163: public String put(String key, InetAddress value) {
164: return this .put(key, value.toString());
165: }
166:
167: /**
168: * Add a String to the map. The content of the String is escaped to be usable in HTML output.
169: * @param key key name as String.
170: * @param value a String that will be reencoded for HTML output.
171: * @return the modified String that was added to the map.
172: * @see htmlTools#encodeUnicode2html(String, boolean)
173: */
174: public String putHTML(String key, String value) {
175: return putHTML(key, value, false);
176: }
177:
178: /**
179: * Like {@link #putHTML(String, String)} but takes an extra argument defining, if the returned
180: * String should be used in normal HTML: <code>false</code>.
181: * If forXML is <code>true</code>, then only the characters <b>& " < ></b> will be
182: * replaced in the returned String.
183: */
184: public String putHTML(String key, String value, boolean forXML) {
185: return (String) put(key, htmlTools.encodeUnicode2html(value,
186: true, forXML));
187: }
188:
189: /**
190: * Add a byte/long/integer to the map. The number will be encoded into a String using
191: * a localized format specified by {@link yFormatter} and {@link #setLocalized(boolean)}.
192: * @param key key name as String.
193: * @param value integer type value to be added to the map in its formatted String
194: * representation.
195: * @return the String value added to the map.
196: */
197: public String putNum(String key, long value) {
198: return (String) this .put(key, yFormatter.number(value,
199: this .localized));
200: }
201:
202: /**
203: * Variant for double/float types.
204: * @see #putNum(String, long)
205: */
206: public String putNum(String key, double value) {
207: return (String) this .put(key, yFormatter.number(value,
208: this .localized));
209: }
210:
211: /**
212: * Variant for string encoded numbers.
213: * @see #putNum(String, long)
214: */
215: public String putNum(String key, String value) {
216: return (String) this .put(key, yFormatter.number(value));
217: }
218:
219: public String putWiki(String key, String wikiCode) {
220: return (String) this .put(key, plasmaSwitchboard.wikiParser
221: .transform(wikiCode));
222: }
223:
224: public String putWiki(String key, byte[] wikiCode) {
225: try {
226: return (String) this .put(key, plasmaSwitchboard.wikiParser
227: .transform(wikiCode));
228: } catch (UnsupportedEncodingException e) {
229: return (String) this .put(key,
230: "Internal error pasting wiki-code: "
231: + e.getMessage());
232: }
233: }
234:
235: public String putWiki(String key, String wikiCode,
236: String publicAddress) {
237: return (String) this .put(key, plasmaSwitchboard.wikiParser
238: .transform(wikiCode, publicAddress));
239: }
240:
241: public String putWiki(String key, byte[] wikiCode,
242: String publicAddress) {
243: try {
244: return (String) this .put(key, plasmaSwitchboard.wikiParser
245: .transform(wikiCode, "UTF-8", publicAddress));
246: } catch (UnsupportedEncodingException e) {
247: return (String) this .put(key,
248: "Internal error pasting wiki-code: "
249: + e.getMessage());
250: }
251: }
252:
253: // inc variant: for counters
254: public long inc(String key) {
255: String c = (String) super .get(key);
256: if (c == null)
257: c = "0";
258: long l = Long.parseLong(c) + 1;
259: super .put(key, Long.toString(l));
260: return l;
261: }
262:
263: // new get with default objects
264: public Object get(String key, Object dflt) {
265: Object result = super .get(key);
266: if (result == null)
267: return dflt;
268: else
269: return result;
270: }
271:
272: // string variant
273: public String get(String key, String dflt) {
274: Object result = super .get(key);
275: if (result == null)
276: return dflt;
277: else
278: return (String) result;
279: }
280:
281: public int getInt(String key, int dflt) {
282: String s = (String) super .get(key);
283: if (s == null)
284: return dflt;
285: try {
286: return Integer.parseInt(s);
287: } catch (NumberFormatException e) {
288: return dflt;
289: }
290: }
291:
292: public long getLong(String key, long dflt) {
293: String s = (String) super .get(key);
294: if (s == null)
295: return dflt;
296: try {
297: return Long.parseLong(s);
298: } catch (NumberFormatException e) {
299: return dflt;
300: }
301: }
302:
303: // returns a set of all values where their key mappes the keyMapper
304: public String[] getAll(String keyMapper) {
305: // the keyMapper may contain regular expressions as defined in String.matches
306: // this method is particulary useful when parsing the result of checkbox forms
307: ArrayList<String> v = new ArrayList<String>();
308: Iterator<String> e = keySet().iterator();
309: String key;
310: while (e.hasNext()) {
311: key = e.next();
312: if (key.matches(keyMapper))
313: v.add((String) get(key));
314: }
315: // make a String[]
316: String[] result = new String[v.size()];
317: for (int i = 0; i < v.size(); i++)
318: result[i] = (String) v.get(i);
319: return result;
320: }
321:
322: // put all elements of another hashtable into the own table
323: public void putAll(serverObjects add) {
324: Iterator<String> e = add.keySet().iterator();
325: String k;
326: while (e.hasNext()) {
327: k = e.next();
328: put(k, add.get(k));
329: }
330: }
331:
332: // convenience methods for storing and loading to a file system
333: public void store(File f) throws IOException {
334: BufferedOutputStream fos = null;
335: try {
336: fos = new BufferedOutputStream(new FileOutputStream(f));
337: Iterator<String> e = keySet().iterator();
338: String key, value;
339: while (e.hasNext()) {
340: key = e.next();
341: value = get(key).replaceAll("\n", "\\\\n");
342: fos.write((key + "=" + value + "\r\n").getBytes());
343: }
344: } finally {
345: if (fos != null) {
346: try {
347: fos.flush();
348: fos.close();
349: } catch (Exception e) {
350: }
351: }
352: }
353: }
354:
355: /**
356: * Defines the localization state of this object.
357: * Currently it is used for numbers added with the putNum() methods only.
358: * @param loc if <code>true</code> store numbers in a localized format, otherwise
359: * use a default english locale without grouping.
360: * @see yFormatter#setLocale(String)
361: */
362: public void setLocalized(boolean loc) {
363: this .localized = loc;
364: }
365:
366: public Object clone() {
367: return super.clone();
368: }
369:
370: }
|