001: /*
002: * File: Message.java
003: * Project: jMOS, com.aranova.java.jmos
004: * Revision: 0.9 - Inicial
005: * Date: 18-oct-2005 16:48:29
006: *
007: * Copyright (C) Aragón Innovación Tecnológica S.L.L.
008: * All rights reserved.
009: *
010: * This software is distributed under the terms of the Aranova License version 1.0.
011: * See the terms of the Aranova License in the documentation provided with this software.
012: */
013:
014: package com.aranova.java.jmos.messages;
015:
016: import java.io.StringReader;
017: import java.lang.reflect.Field;
018: import java.lang.reflect.Modifier;
019: import java.sql.Time;
020: import java.text.ParseException;
021: import java.text.SimpleDateFormat;
022: import java.util.ArrayList;
023: import java.util.Date;
024: import java.util.HashMap;
025: import java.util.LinkedHashMap;
026: import java.util.Map;
027: import java.util.Set;
028:
029: import javax.xml.stream.XMLEventReader;
030: import javax.xml.stream.XMLInputFactory;
031: import javax.xml.stream.XMLStreamException;
032: import javax.xml.stream.XMLStreamWriter;
033: import javax.xml.stream.events.XMLEvent;
034:
035: import org.apache.commons.logging.Log;
036: import org.apache.commons.logging.LogFactory;
037:
038: import com.aranova.java.jmos.annotations.MOSAttribute;
039: import com.aranova.java.jmos.annotations.MOSMessage;
040: import com.aranova.java.jmos.annotations.MOSProfile;
041: import com.aranova.java.jmos.enums.TypeModifier;
042: import com.aranova.java.jmos.util.Common;
043: import com.aranova.java.jmos.util.Config;
044: import com.aranova.java.util.Reflect;
045: import com.aranova.java.util.Version;
046:
047: /**
048: * Clase base para todos los mensajes MOS.
049: *
050: * @author <a href="http://www.aranova.net/contactar/">Daniel Sánchez</a>
051: * @version 0.9.1
052: * @since 0.9
053: */
054: public class Message {
055: private static final Log _log = LogFactory.getLog(Message.class);
056: private static final SimpleDateFormat _simpleDateFormat;
057: private static final boolean _writeXmlHead;
058: private static final Version _version;
059: private static final Map<String, InfoMessage> _messages;
060: private final String _name;
061: private Map<String, Object> _lostValues;
062:
063: private final ArrayList<ErrorValidation> _listErrors;
064: @MOSAttribute(name="mosID",maxLength=128,namespace="mos")
065: private String _mosID;
066: @MOSAttribute(name="ncsID",maxLength=128,namespace="mos")
067: private String _ncsID;
068: @MOSAttribute(name="messageID",version="2.8.1",namespace="mos")
069: private Long _messageID;
070: private Message _messagePrevio;
071:
072: static {
073: _simpleDateFormat = new SimpleDateFormat(Config.getConfig()
074: .getString("DATEFORMAT"));
075: _writeXmlHead = Config.getConfig().getBoolean("WriteXmlHead");
076: _version = new Version(Config.getConfig().getString("mosRev"));
077: _messages = new HashMap<String, InfoMessage>();
078: initMessages();
079: }
080:
081: @SuppressWarnings("unchecked")
082: private static void initMessages() {
083: Package pack;
084: MOSProfile profile;
085: MOSMessage message;
086: InfoMessage info;
087: MOSAttribute attribute;
088: Class[] clases;
089: String packageName = Message.class.getPackage().getName()
090: + ".profile";
091:
092: try {
093: clases = Reflect.getClasses(packageName);
094: pack = Package.getPackage(packageName);
095: if (pack.isAnnotationPresent(MOSProfile.class)) {
096: profile = pack.getAnnotation(MOSProfile.class);
097: if (profile.version().equals("")
098: || _version.compareTo(new Version(profile
099: .version())) >= 0) {
100: for (Class clazz : clases) {
101: if (clazz.isAnnotationPresent(MOSMessage.class)) {
102: message = (MOSMessage) clazz
103: .getAnnotation(MOSMessage.class);
104: if (message.version().equals("")
105: || _version.compareTo(new Version(
106: message.version())) >= 0) {
107: info = new InfoMessage(message);
108: for (Field field : clazz
109: .getDeclaredFields()) {
110: if (field
111: .isAnnotationPresent(MOSAttribute.class)) {
112: attribute = field
113: .getAnnotation(MOSAttribute.class);
114: if (attribute.version().equals(
115: "")
116: || _version
117: .compareTo(new Version(
118: attribute
119: .version())) >= 0) {
120: info.addField(attribute,
121: field);
122: if (!Modifier
123: .isPublic(field
124: .getModifiers())) {
125: field
126: .setAccessible(true);
127: }
128: }
129: }
130: }
131: _messages.put(info.getMessage().name(),
132: info);
133: }
134: }
135: }
136: }
137: }
138: } catch (ClassNotFoundException e) {
139: throw new Error(
140: "Se ha especificado un perfil no implementado.", e);
141: }
142:
143: final Map<String, InfoAttribute> fields = new LinkedHashMap<String, InfoAttribute>();
144: for (Field field : Message.class.getDeclaredFields()) {
145: if (field.isAnnotationPresent(MOSAttribute.class)) {
146: attribute = field.getAnnotation(MOSAttribute.class);
147: if (attribute.version().equals("")
148: || _version.compareTo(new Version(attribute
149: .version())) >= 0) {
150: fields.put(attribute.name(), new InfoAttribute(
151: attribute, field));
152: if (!Modifier.isPublic(field.getModifiers())) {
153: field.setAccessible(true);
154: }
155: }
156: }
157: }
158:
159: for (int i = 0;; i++) {
160: if (Config.getConfig().getString("mosProfile" + i) == null) {
161: break;
162: }
163: if (Config.getConfig().getBoolean("mosProfile" + i)) {
164: try {
165: clases = Reflect.getClasses(packageName + i);
166: pack = Package.getPackage(packageName + i);
167: if (pack.isAnnotationPresent(MOSProfile.class)) {
168: profile = pack.getAnnotation(MOSProfile.class);
169: if (profile.version().equals("")
170: || _version.compareTo(new Version(
171: profile.version())) >= 0) {
172: for (Class clazz : clases) {
173: if (clazz
174: .isAnnotationPresent(MOSMessage.class)) {
175: message = (MOSMessage) clazz
176: .getAnnotation(MOSMessage.class);
177: if (message.version().equals("")
178: || _version
179: .compareTo(new Version(
180: message
181: .version())) >= 0) {
182: info = new InfoMessage(message);
183: info.addFields(fields);
184: for (Field field : clazz
185: .getDeclaredFields()) {
186: if (field
187: .isAnnotationPresent(MOSAttribute.class)) {
188: attribute = field
189: .getAnnotation(MOSAttribute.class);
190: if (attribute.version()
191: .equals("")
192: || _version
193: .compareTo(new Version(
194: attribute
195: .version())) >= 0) {
196: info.addField(
197: attribute,
198: field);
199: if (!Modifier
200: .isPublic(field
201: .getModifiers())) {
202: field
203: .setAccessible(true);
204: }
205: }
206: }
207: }
208: _messages.put(info.getMessage()
209: .name(), info);
210: }
211: }
212: }
213: }
214: }
215: } catch (ClassNotFoundException e) {
216: throw new Error(
217: "Se ha especificado un perfil no implementado.",
218: e);
219: }
220: }
221: }
222: }
223:
224: /**
225: * Set mosID and ncsID for response.
226: * @param base Message original
227: */
228: public void setResponseInfoFrom(final Message base) {
229: _mosID = base.getMosID();
230: _ncsID = base.getNcsID();
231: }
232:
233: /**
234: * Contrsuctor de la clase.
235: */
236: protected Message() {
237: super ();
238: _listErrors = new ArrayList<ErrorValidation>();
239: _name = this .getClass().getAnnotation(MOSMessage.class).name();
240: }
241:
242: /**
243: * @return The name of message.
244: */
245: public String getName() {
246: return _name;
247: }
248:
249: /**
250: * @param name
251: * @param value
252: */
253: @SuppressWarnings("unchecked")
254: public void set(final String name, final Object value) {
255: try {
256: final Field field = _messages.get(_name).getField(name);
257: if (field == null) {
258: _log.warn("No existe el campo " + name
259: + " en el mensaje " + _name);
260: if (_lostValues == null) {
261: _lostValues = new LinkedHashMap<String, Object>();
262: }
263: _lostValues.put(name, value);
264: return;
265: }
266: final Class type = field.getType();
267: if (type == Set.class) {
268: //TODO Pasar las conversiones de tipos antes de añadir estos valores.
269: ((Set) field.get(this )).add(value);
270: return;
271: }
272: if (Message.class.isInstance(value)) {
273: field.set(this , value);
274: return;
275: }
276: String stringVal = value.toString();
277: if (type.equals(String.class)) {
278: String previous = (String) field.get(this );
279: if (previous != null) {
280: field.set(this , previous + stringVal);
281: } else {
282: field.set(this , stringVal);
283: }
284: return;
285: }
286: if (type.isEnum()) {
287: stringVal = stringVal.replace(' ', '_');
288: field.set(this , Enum.valueOf((Class<Enum>) type,
289: stringVal));
290: return;
291: }
292: if (type.equals(Integer.class)) {
293: field.set(this , Integer.parseInt(stringVal));
294: return;
295: }
296: if (type.equals(Long.class)) {
297: field.set(this , Long.parseLong(stringVal));
298: return;
299: }
300: if (type.equals(Date.class)) {
301: field.set(this , _simpleDateFormat.parse(stringVal));
302: return;
303: }
304: if (type.equals(Time.class)) {
305: field.set(this , Time.valueOf(stringVal));
306: return;
307: }
308: if (type.equals(Boolean.class)) {
309: if (stringVal.equalsIgnoreCase("YES")) {
310: field.set(this , true);
311: } else if (stringVal.equalsIgnoreCase("NO")) {
312: field.set(this , false);
313: } else {
314: field.set(this , Boolean.parseBoolean(stringVal));
315: }
316: return;
317: }
318: } catch (SecurityException e) {
319: _log.warn("Error al establecer el valor del campo: " + name
320: + " con valor: " + value, e);
321: } catch (IllegalArgumentException e) {
322: _log.warn("Error al establecer el valor del campo: " + name
323: + " con valor: " + value, e);
324: } catch (IllegalAccessException e) {
325: _log.warn("Error al establecer el valor del campo: " + name
326: + " con valor: " + value, e);
327: } catch (ParseException e) {
328: _log.warn("Error al establecer el valor del campo: " + name
329: + " con valor: " + value, e);
330: }
331: }
332:
333: /**
334: * Valida el mensaje anter de enviarlo.
335: * @return True or false
336: */
337: public boolean validate() {
338: _listErrors.clear();
339: validate(_listErrors);
340: return _listErrors.size() == 0;
341: }
342:
343: /**
344: * Valida el mensaje.
345: * @param listErrors
346: */
347: @SuppressWarnings("unchecked")
348: protected void validate(final ArrayList<ErrorValidation> listErrors) {
349: Field field = null;
350: MOSAttribute fieldAtt;
351:
352: _log.info("Validating document " + _name);
353: InfoMessage infoMessage = _messages.get(_name);
354: for (InfoAttribute info : infoMessage.getFields().values()) {
355: fieldAtt = info.getAttribute();
356: if (fieldAtt.namespace().equals("mos")) {
357: continue;
358: }
359: field = info.getField();
360: Object value = null;
361: try {
362: value = field.get(this );
363: } catch (IllegalArgumentException e) {
364: _log.warn("Error al recuperar el valor del campo:"
365: + field.getName() + " en el mensaje: " + _name,
366: e);
367: } catch (IllegalAccessException e) {
368: _log.warn("Error al recuperar el valor del campo:"
369: + field.getName() + " en el mensaje: " + _name,
370: e);
371: } catch (SecurityException e) {
372: _log.warn("Error al recuperar el valor del campo:"
373: + field.getName() + " en el mensaje: " + _name,
374: e);
375: }
376: if (value instanceof Set) {
377: Set new_value = (Set) value;
378: for (Object o : new_value) {
379: if (o instanceof Message) {
380: ((Message) o).validate(listErrors);
381: }
382: }
383: }
384: if (value instanceof Message) {
385: ((Message) value).validate(listErrors);
386: }
387: switch (fieldAtt.modifier()) {
388: case Optional:
389: break;
390: case ZeroOrMore:
391: break;
392: case OneOrMore:
393: if (value == null || ((Set) value).size() == 0) {
394: _listErrors.add(new ErrorValidation(
395: fieldAtt.name(), fieldAtt.modifier()));
396: }
397: break;
398: case Required:
399: if (value == null) {
400: _listErrors.add(new ErrorValidation(
401: fieldAtt.name(), fieldAtt.modifier()));
402: }
403: break;
404: }
405: }
406: }
407:
408: /**
409: * Write fields into XML stream.
410: * @param writer
411: * @param writeMosFields
412: * @throws XMLStreamException
413: */
414: @SuppressWarnings("unchecked")
415: protected void writeFields(final XMLStreamWriter writer,
416: final boolean writeMosFields) throws XMLStreamException {
417: Field field = null;
418: MOSAttribute fieldAtt;
419: String namespace = null;
420: String namespaceOld = null;
421: boolean writeEnd = false;
422: InfoMessage infoMessage = _messages.get(_name);
423: for (InfoAttribute info : infoMessage.getFields().values()) {
424: fieldAtt = info.getAttribute();
425: namespace = fieldAtt.namespace();
426: if (namespace.equalsIgnoreCase("mos")) {
427: if (!writeMosFields) {
428: continue;
429: }
430: } else if (!namespace.equals(namespaceOld)) {
431: if (writeEnd) {
432: if (!namespace.equals("")
433: || infoMessage.getMessage().writeTag()) {
434: writer.writeEndElement();
435: }
436: }
437: if (namespace.equals("")) {
438: if (infoMessage.getMessage().writeTag()) {
439: writer.writeStartElement(_name);
440: }
441: } else {
442: writer.writeStartElement(namespace);
443: }
444: namespaceOld = namespace;
445: writeEnd = true;
446: }
447: field = info.getField();
448: Object value = null;
449: try {
450: value = field.get(this );
451: } catch (IllegalArgumentException e) {
452: _log.warn("Error al recuperar el valor del campo:"
453: + field.getName() + " en el mensaje: " + _name,
454: e);
455: } catch (IllegalAccessException e) {
456: _log.warn("Error al recuperar el valor del campo:"
457: + field.getName() + " en el mensaje: " + _name,
458: e);
459: } catch (SecurityException e) {
460: _log.warn("Error al recuperar el valor del campo:"
461: + field.getName() + " en el mensaje: " + _name,
462: e);
463: }
464: if (value != null) {
465: if (fieldAtt.writeTag()) {
466: writer.writeStartElement(fieldAtt.name());
467: }
468: if (field.getType().isEnum()) {
469: if (fieldAtt.attibute()) {
470: writer.writeAttribute(fieldAtt.name(),
471: ((Enum) value).name().replaceAll("_",
472: " "));
473: } else {
474: writer.writeCharacters(((Enum) value).name()
475: .replaceAll("_", " "));
476: }
477: } else if (field.getType().equals(Date.class)) {
478: if (fieldAtt.attibute()) {
479: writer.writeAttribute(fieldAtt.name(),
480: _simpleDateFormat.format((Date) value));
481: } else {
482: writer.writeCharacters(_simpleDateFormat
483: .format((Date) value));
484: }
485: } else if (field.getType().equals(Time.class)) {
486: if (fieldAtt.attibute()) {
487: writer.writeAttribute(fieldAtt.name(),
488: ((Time) value).toString());
489: } else {
490: writer.writeCharacters(((Time) value)
491: .toString());
492: }
493: } else if (value instanceof Set) {
494: Set new_value = (Set) value;
495: if (new_value.size() > 0) {
496: if (fieldAtt.tagForItem().equals("")) {
497: for (Object message : new_value) {
498: if (message instanceof Message) {
499: ((Message) message).writeFields(
500: writer, false);
501: } else {
502: writer.writeCharacters(message
503: .toString());
504: }
505: }
506: } else {
507: for (Object message : new_value) {
508: writer.writeStartElement(fieldAtt
509: .tagForItem());
510: if (message instanceof Message) {
511: ((Message) message).writeFields(
512: writer, false);
513: } else {
514: writer.writeCharacters(message
515: .toString());
516: }
517: writer.writeEndElement();
518: }
519: }
520: }
521: } else if (value instanceof Message) {
522: ((Message) value).writeFields(writer, false);
523: } else if (fieldAtt.isXML()) {
524: copyXML(fieldAtt.name(), value.toString(), writer);
525: } else if (value instanceof Boolean) {
526: if ((Boolean) value) {
527: writer.writeCharacters("YES");
528: } else {
529: writer.writeCharacters("NO");
530: }
531: } else {
532: if (fieldAtt.attibute()) {
533: writer.writeAttribute(fieldAtt.name(), value
534: .toString());
535: } else {
536: writer.writeCharacters(value.toString());
537: }
538: }
539: if (fieldAtt.writeTag()) {
540: writer.writeEndElement();
541: }
542: } else {
543: if (fieldAtt.modifier() != TypeModifier.Optional) {
544: writer.writeStartElement(fieldAtt.name());
545: writer.writeEndElement();
546: }
547: }
548: }
549: if (writeEnd) {
550: if (!namespace.equals("")
551: || infoMessage.getMessage().writeTag()) {
552: writer.writeEndElement();
553: }
554: } else {
555: writer.writeStartElement(_name);
556: writer.writeEndElement();
557: }
558: }
559:
560: private static void copyXML(final String fieldName,
561: final String textXML, final XMLStreamWriter writer)
562: throws XMLStreamException {
563: XMLInputFactory factory = XMLInputFactory.newInstance();
564: StringBuilder builder = new StringBuilder();
565: builder.append('<');
566: builder.append(fieldName);
567: builder.append('>');
568: builder.append(textXML);
569: builder.append("</");
570: builder.append(fieldName);
571: builder.append('>');
572: try {
573: XMLEventReader reader = factory
574: .createXMLEventReader(new StringReader(builder
575: .toString()));
576: while (reader.hasNext()) {
577: XMLEvent event = reader.nextEvent();
578: switch (event.getEventType()) {
579: case XMLEvent.START_ELEMENT:
580: writer.writeStartElement(event.asStartElement()
581: .getName().toString());
582: break;
583: case XMLEvent.END_ELEMENT:
584: writer.writeEndElement();
585: break;
586: case XMLEvent.CHARACTERS:
587: writer.writeCharacters(event.asCharacters()
588: .getData());
589: break;
590: default:
591: break;
592: }
593: }
594: } catch (XMLStreamException e) {
595: _log.error("Error al copiar el XML del campo: " + fieldName
596: + " con valor: " + textXML);
597: throw e;
598: }
599: }
600:
601: /**
602: * Write de message.
603: * @param writer
604: * @throws XMLStreamException
605: */
606: public void write(final XMLStreamWriter writer)
607: throws XMLStreamException {
608: write(writer, true);
609: }
610:
611: /**
612: * Write de message.
613: * @param writer
614: * @param writeEndElement
615: * @throws XMLStreamException
616: */
617: public final void write(final XMLStreamWriter writer,
618: final boolean writeEndElement) throws XMLStreamException {
619: _log.info("Create document " + _name);
620: if (_writeXmlHead) {
621: writer.writeStartDocument(Common.getEncoding(), "1.0");
622: //writer.writeDTD("<!DOCTYPE Recipe SYSTEM \"example.dtd\">");
623: }
624: writer.writeStartElement("mos");
625: writeFields(writer, true);
626: if (writeEndElement) {
627: writer.writeEndDocument();
628: }
629: }
630:
631: /**
632: * @return Returns the messageID.
633: */
634: public Long getMessageID() {
635: return _messageID;
636: }
637:
638: /**
639: * @param messageID The messageID to set.
640: */
641: public void setMessageID(final Long messageID) {
642: _messageID = messageID;
643: }
644:
645: /**
646: * @return Returns the mosID.
647: */
648: public String getMosID() {
649: return _mosID;
650: }
651:
652: /**
653: * @param mosID The mosID to set.
654: */
655: public void setMosID(final String mosID) {
656: _mosID = mosID;
657: }
658:
659: /**
660: * @return Returns the ncsID.
661: */
662: public String getNcsID() {
663: return _ncsID;
664: }
665:
666: /**
667: * @param ncsID The ncsID to set.
668: */
669: public void setNcsID(final String ncsID) {
670: _ncsID = ncsID;
671: }
672:
673: /**
674: * @return Returns the messages.
675: */
676: public static Map<String, InfoMessage> getMessages() {
677: return _messages;
678: }
679:
680: /**
681: * @return Returns the listErrors.
682: */
683: public ArrayList<ErrorValidation> getListErrors() {
684: return _listErrors;
685: }
686:
687: /**
688: * @return Returns the messagePrevio.
689: */
690: public Message getMessagePrevio() {
691: return _messagePrevio;
692: }
693:
694: /**
695: * @param messagePrevio The messagePrevio to set.
696: */
697: public void setMessagePrevio(final Message messagePrevio) {
698: _messagePrevio = messagePrevio;
699: }
700:
701: /**
702: * @return Returns the lostValues.
703: */
704: public Map<String, Object> getLostValues() {
705: return _lostValues;
706: }
707: }
|