Statistics
| Revision:

gvsig-tools / org.gvsig.tools / library / trunk / org.gvsig.tools / org.gvsig.tools.lib / src / main / java / org / gvsig / tools / persistence / xml / XMLPersistentStateWriter.java @ 719

History | View | Annotate | Download (13.8 KB)

1
/* gvSIG. Geographic Information System of the Valencian Government
2
 *
3
 * Copyright (C) 2007-2008 Infrastructures and Transports Department
4
 * of the Valencian Government (CIT)
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., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 */
22

    
23
/*
24
 * AUTHORS (In addition to CIT):
25
 * 2009 IVER T.I   {{Task}}
26
 */
27

    
28
/**
29
 *
30
 */
31
package org.gvsig.tools.persistence.xml;
32

    
33
import java.io.File;
34
import java.io.OutputStream;
35
import java.io.OutputStreamWriter;
36
import java.io.PrintWriter;
37
import java.lang.reflect.Method;
38
import java.net.URI;
39
import java.net.URL;
40
import java.text.MessageFormat;
41
import java.util.Date;
42
import java.util.Iterator;
43
import java.util.List;
44
import java.util.Map;
45
import java.util.Map.Entry;
46
import java.util.Set;
47
import java.util.regex.Pattern;
48

    
49
import org.gvsig.tools.dynobject.DynStruct;
50
import org.gvsig.tools.persistence.PersistenceFactory;
51
import org.gvsig.tools.persistence.PersistentContext;
52
import org.gvsig.tools.persistence.exception.PersistenceException;
53
import org.gvsig.tools.persistence.exception.PersistenceTypeNotSupportedException;
54
import org.gvsig.tools.persistence.spi.PersistentContextServices.ObjectReference;
55
import org.gvsig.tools.persistence.spi.PersistentStateServices;
56

    
57
/**
58
 * @author jmvivo
59
 *
60
 */
61
public class XMLPersistentStateWriter implements XMLPersistentConstants {
62

    
63
        private static Method getCharSetMethod = null;
64
        private static Method getCharSetNameMethod = null;
65

    
66
        private XMLPersistenceManager manager;
67
        private PrintWriter print;
68
        private boolean useCsMap = false;
69
        private boolean useDomains = false;
70

    
71
        private final static Pattern DOT_PATTERN = Pattern.compile("[.]");
72

    
73
    /**
74
     * The Unix separator character.
75
     */
76
    private static final char UNIX_SEPARATOR = '/';
77

    
78
    /**
79
     * Is it a Unix-like system?
80
     */
81
    private final static boolean UNIX_SYSTEM =
82
        File.separatorChar == UNIX_SEPARATOR;
83

    
84
    /**
85
     * The Windows separator character.
86
     */
87
    private static final char WINDOWS_SEPARATOR = '\\';
88

    
89
        public XMLPersistentStateWriter(XMLPersistenceManager persistenceManager) {
90
                this.manager = persistenceManager;
91
        }
92

    
93
        public void write(PersistentStateServices state, OutputStream out)
94
                        throws PersistenceException {
95
                write(state, out, null);
96
        }
97

    
98
        public void write(PersistentStateServices state, OutputStream out,
99
                        Map domains)
100
                        throws PersistenceException {
101
                PersistentStateServices  root = state;
102
                String rootId = root.getId().toString();
103
                PersistentContext context = state.getContext();
104
                OutputStreamWriter outWrite = new OutputStreamWriter(out);
105
                print = new PrintWriter(out);
106

    
107
                // XML header (<?xml ....?>)
108
                print.println(MessageFormat.format(XML_HEADER,
109
                                new String[] { getCharset(outWrite.getEncoding()) }));
110

    
111
                // Prepare schema
112
                String rootAttributes = "";
113
                if (domains != null && domains.size() > 0) {
114
                        useDomains = true;
115
                        StringBuffer buffRootAttr = new StringBuffer();
116

    
117
                        buffRootAttr.append('\n');
118
                        buffRootAttr.append(MessageFormat.format(
119
                                        DOMAIN_NAME_ATTRIBUTE_VALUE, new Object[] {
120
                                                        BASE_DOMIAN_NAME, BASE_DOMIAN_URL }));
121
                        Iterator iter = domains.entrySet().iterator();
122
                        Entry entry;
123
                        while (iter.hasNext()) {
124
                                entry = (Entry) iter.next();
125
                                buffRootAttr.append('\n');
126
                                buffRootAttr.append(MessageFormat.format(DOMAIN_NAME_ATTRIBUTE_VALUE,
127
                                                new Object[] { entry.getKey(), entry.getValue() }));
128
                        }
129
                        iter = domains.entrySet().iterator();
130
                        StringBuffer buffSchemas = new StringBuffer();
131

    
132
                        buffSchemas.append('\n');
133
                        buffSchemas.append(MessageFormat.format(SCHEMA_DEFINITON_VALUE,
134
                                        new Object[] { BASE_DOMIAN_NAME, BASE_DOMIAN_URL }));
135
                        while (iter.hasNext()) {
136
                                entry = (Entry) iter.next();
137
                                buffSchemas.append('\n');
138
                                buffSchemas.append(MessageFormat.format(SCHEMA_DEFINITON_VALUE,
139
                                                new Object[] { entry.getValue(), entry.getKey() }));
140
                        }
141
                        buffRootAttr.append('\n');
142
                        buffRootAttr.append(MessageFormat.format(DEFAULT_SCHEMA_ATTRIBUTE_VALUE,
143
                                        new Object[] { buffSchemas.toString() }));
144
                        rootAttributes = buffRootAttr.toString();
145
                }
146

    
147
                // Root tag:
148
//                if (useDomains) {
149
//                        print.println(MessageFormat.format(ROOT_VALUE, new Object[] {
150
//                                        BASE_DOMIAN_NAME + ":", rootAttributes }));
151
//                } else {
152
                        print.println(MessageFormat.format(ROOT_VALUE,
153
                                        new Object[] { "",
154
                                        rootAttributes }));
155
//                }
156

    
157
                // Version
158
                print.println(MessageFormat.format(VERSION_VALUE,
159
                                new Object[] { manager.version() }));
160

    
161
                // add root state id
162
                print.println(MessageFormat.format(ROOTSTATE_VALUE,
163
                                new String[] { rootId }));
164

    
165
                PersistentStateServices curState;
166
                Iterator itStates = context.iterator();
167

    
168
                // States tag:
169
                print.println(STATES_START);
170

    
171
                // iter all states
172
                while (itStates.hasNext()) {
173
                        curState = (PersistentStateServices) itStates.next();
174
                        writeState(curState);
175

    
176
                }
177
                // States end:
178
                print.println(STATES_END);
179

    
180
                // Root end:
181
//                if (useDomains) {
182
//                        print.println(MessageFormat.format(ROOT_END_VALUE,
183
//                                        new Object[] { BASE_DOMIAN_NAME + ":" }));
184
//                } else {
185
                        print.println(MessageFormat.format(ROOT_END_VALUE,
186
                                        new Object[] { "" }));
187
//                }
188

    
189
                print.flush();
190

    
191
        }
192

    
193
        private void writeState(PersistentStateServices curState)
194
                        throws PersistenceException {
195
                Iterator itNames;
196
                String name;
197
                Object value;
198

    
199
                itNames = curState.getNames();
200
                String theClassName = curState.getTheClassName();
201
                String tagName = getXMLValidName( theClassName);
202
                DynStruct definition = curState.getDefinition();
203
                if( definition != null ) {
204
                        tagName = getXMLValidName(  curState.getDefinition().getFullName() );                        
205
                }
206

    
207
                String domainName = "";
208
                if (useDomains) {
209
                        PersistenceFactory factory =  manager.getFactories().get(theClassName);
210
                        domainName = factory.getDomainName() + ":";
211
                }
212

    
213
                // add state start
214
                print.println(MessageFormat.format(STATE_START, new Object[] {
215
                                domainName, tagName, curState.getId() }));
216

    
217
                boolean useNameAsTag;
218
                String format, type;
219
                StringBuffer strb;
220
                // iter all property names
221
                while (itNames.hasNext()) {
222
                        name = (String) itNames.next();
223
                        
224
                        value = curState.getValue(name);
225
                        strb = new StringBuffer();
226
                        type = transformValue(value, strb);
227

    
228
                        useNameAsTag = VALID_TAG_PATTERN.matcher(name).matches();
229

    
230
                        if (useNameAsTag) {
231
                                format = VALUE_ITEM;
232
                        } else {
233
                                format = VALUE_ITEM_GENERIC;
234
                        }
235

    
236
                        print.println(MessageFormat.format(format, new String[] { name,
237
                                        type, strb.toString() }));
238

    
239
                }
240

    
241
                // add state end
242
                print.println(MessageFormat.format(STATE_END, new Object[] {
243
                                domainName, tagName, curState.getId() }));
244

    
245
        }
246

    
247
        public static String getXMLValidName(String theClassName) {
248
                String name = theClassName;
249
                // Remove all $ chars for inner class names
250
                int pos = 0;
251
                while ((pos = name.indexOf('$')) > 0) {
252
                        name =
253
                                        name.substring(0, pos).concat("..").concat(
254
                                                        name.substring(pos + 1));
255
                }
256
                while ((pos = name.indexOf(':')) > 0) {
257
                        name =
258
                                        name.substring(0, pos).concat("__").concat(
259
                                                        name.substring(pos + 1));
260
                }
261
                return name;
262
        }
263

    
264
        private String transformValue(Object value, StringBuffer strb)
265
                        throws PersistenceTypeNotSupportedException {
266
                if (value instanceof String) {
267
                        return transformValue((String) value, strb);
268
                } else if (value instanceof Number) {
269
                        return transformValue((Number) value, strb);
270
                } else if (value instanceof ObjectReference) {
271
                        return transformValue((ObjectReference) value, strb);
272
                } else if (value instanceof List) {
273
                        return transformValue((List) value, strb);
274
                } else if (value instanceof Set) {
275
                        return transformValue((Set) value, strb);
276
                } else if (value instanceof Map) {
277
                        return transformValue((Map) value, strb);
278
                } else if (value instanceof Boolean) {
279
                        return transformValue((Boolean) value, strb);
280
                } else if (value instanceof Date) {
281
                        return transformValue((Date) value, strb);
282
                } else if (value instanceof File) {
283
                        return transformValue((File) value, strb);
284
                } else if (value instanceof URL) {
285
                        return transformValue((URL) value, strb);
286
                } else if (value instanceof URI) {
287
                        return transformValue((URI) value, strb);
288
                } else if (value == null) {
289
                        return transformNullValue(strb);
290
                } else {
291
                        throw new PersistenceTypeNotSupportedException(value.getClass());
292
                }
293
        }
294

    
295
        private String transformValue(String value, StringBuffer strb) {
296
                if (!VALID_VALUE_PATTERN.matcher(value).matches()) {
297
                        strb.append(CDATA_START);
298
                        strb.append(value);
299
                        strb.append(CDATA_END);
300
                } else {
301
                        strb.append(value);
302
                }
303
                return TYPE_STRING;
304
        }
305

    
306
        private String transformValue(File value, StringBuffer strb) {
307
                String data;
308
                data = value.getPath();
309
        if (!UNIX_SYSTEM) {
310
            // Always use UNIX separator as it's allowed in both system
311
            data = data.replace(WINDOWS_SEPARATOR, UNIX_SEPARATOR);
312
        }
313
                if (!VALID_VALUE_PATTERN.matcher(data).matches()) {
314
                        strb.append(CDATA_START);
315
                        strb.append(data);
316
                        strb.append(CDATA_END);
317
                } else {
318
                        strb.append(data);
319
                }
320
                return TYPE_FILE;
321
        }
322

    
323
        private String transformValue(URL value, StringBuffer strb) {
324
                String data;
325
                data = value.toExternalForm();
326
                if (!VALID_VALUE_PATTERN.matcher(data).matches()) {
327
                        strb.append(CDATA_START);
328
                        strb.append(data);
329
                        strb.append(CDATA_END);
330
                } else {
331
                        strb.append(data);
332
                }
333
                return TYPE_URL;
334
        }
335

    
336
        private String transformValue(URI value, StringBuffer strb) {
337
                String data;
338
                data = value.toASCIIString();
339
                if (!VALID_VALUE_PATTERN.matcher(data).matches()) {
340
                        strb.append(CDATA_START);
341
                        strb.append(data);
342
                        strb.append(CDATA_END);
343
                } else {
344
                        strb.append(data);
345
                }
346
                return TYPE_URI;
347
        }
348
        
349
        private String transformNullValue(StringBuffer strb) {
350
                return TYPE_NULL;
351
        }
352

    
353
        private String transformValue(Number value, StringBuffer strb) {
354
                strb.append(value);
355
                String[] classname = split(value.getClass().getName(), DOT_PATTERN);
356
                return classname[classname.length - 1].toLowerCase();
357
        }
358

    
359
//        private String[] split(String txt, String pattern) {
360
//                return Pattern.compile(pattern).split(txt, 0);
361
//        }
362

    
363
        private String[] split(String txt, Pattern pattern) {
364
                return pattern.split(txt, 0);
365
        }
366

    
367
        private String transformValue(Boolean value, StringBuffer strb) {
368
                strb.append(value);
369
                return TYPE_BOOLEAN;
370
        }
371

    
372
        private String transformValue(Date value, StringBuffer strb) {
373
                strb.append(value.getTime());
374
                return TYPE_DATE;
375
        }
376

    
377
        private String transformValue(ObjectReference value, StringBuffer strb) {
378
                strb.append(MessageFormat.format(REFERENCE_VALUE, new Object[] { value
379
                                .getId() }));
380
                strb.append('\n');
381
                strb.append(INDENDT_2);
382
                return TYPE_REFERENCE;
383
        }
384

    
385
        private String transformValue(List value, StringBuffer strb)
386
                        throws PersistenceTypeNotSupportedException {
387
                Iterator iter = value.iterator();
388
                String type;
389
                StringBuffer itemStrb;
390
                while (iter.hasNext()) {
391
                        strb.append('\n');
392
                        itemStrb = new StringBuffer();
393
                        type = transformValue(iter.next(), itemStrb);
394
                        if( TYPE_REFERENCE.equalsIgnoreCase(type)) {
395
                                strb.append(MessageFormat.format(LISTITEM_VALUE, new String[] {
396
                                                type, itemStrb.toString()+INDENDT_1 }));
397
                        } else {
398
                                strb.append(MessageFormat.format(LISTITEM_VALUE, new String[] {
399
                                                type, itemStrb.toString() }));
400
                        }
401
                }
402
                strb.append('\n');
403
                strb.append(INDENDT_2);
404

    
405
                return TYPE_LIST;
406
        }
407

    
408
        private String transformValue(Set value, StringBuffer strb)
409
                        throws PersistenceTypeNotSupportedException {
410
                Iterator iter = value.iterator();
411
                String type;
412
                StringBuffer itemStrb;
413
                while (iter.hasNext()) {
414
                        itemStrb = new StringBuffer();
415
                        type = transformValue(iter.next(), itemStrb);
416
                        strb.append(MessageFormat.format(SETITEM_VALUE, new String[] {
417
                                        type, itemStrb.toString() }));
418
                }
419

    
420
                return TYPE_SET;
421
        }
422

    
423
        private String transformValue(Map value, StringBuffer strb)
424
                        throws PersistenceTypeNotSupportedException {
425
                Iterator iter = value.entrySet().iterator();
426
                Entry entry;
427
                String keyType, valueType;
428
                StringBuffer valueStrb, keyStrb;
429
                while (iter.hasNext()) {
430
                        entry = (Entry) iter.next();
431
                        // transform key
432
                        keyStrb = new StringBuffer();
433
                        keyType = transformValue(entry.getKey(), keyStrb);
434
                        // transform value
435
                        valueStrb = new StringBuffer();
436
                        valueType = transformValue(entry.getValue(), valueStrb);
437

    
438
                        strb.append(MessageFormat.format(MAPITEM_VALUE, new String[] {
439
                                        keyType, keyStrb.toString(), valueType,
440
                                        valueStrb.toString() }));
441
                }
442

    
443
                return TYPE_MAP;
444
        }
445

    
446
        private String getCharsetByNio(String csName) {
447
                Object charSet;
448
                if (getCharSetNameMethod == null) {
449
                        Class charsetClass = null;
450
                        try {
451
                                charsetClass = Class.forName("java.nio.charset.Charset");
452
                        } catch (ClassNotFoundException e) {
453
                                useCsMap = true;
454
                                return null;
455
                        }
456
                        try {
457
                                getCharSetMethod = charsetClass.getMethod("forName",
458
                                                new Class[] { String.class });
459
                        } catch (Exception e) {
460
                                useCsMap = true;
461
                                return null;
462
                        }
463
                        try {
464
                                getCharSetNameMethod = charsetClass.getMethod("displayName",
465
                                                new Class[] {});
466
                        } catch (Exception e) {
467
                                useCsMap = true;
468
                                return null;
469
                        }
470

    
471
                }
472
                try {
473
                        charSet = getCharSetMethod.invoke(null, new Object[] { csName });
474
                } catch (Exception e) {
475
                        useCsMap = true;
476
                        return null;
477
                }
478

    
479
                try {
480
                        return (String) getCharSetNameMethod.invoke(charSet,
481
                                        new Object[] {});
482
                } catch (Exception e) {
483
                        useCsMap = true;
484
                        return null;
485
                }
486
        }
487

    
488
        private String getCharset(String csName) {
489
                if (!useCsMap) {
490
                        String name = this.getCharsetByNio(csName);
491
                        if (name != null) {
492
                                return name;
493
                        }
494
                }
495
                return (String) ChasetMap.getMap().get(csName);
496
        }
497
}