Coverage Report - org.kuali.rice.ken.util.Util
 
Classes in this File Line Coverage Branch Coverage Complexity
Util
0%
0/116
0%
0/28
2.1
Util$1
0%
0/7
N/A
2.1
 
 1  
 /**
 2  
  * Copyright 2005-2011 The Kuali Foundation
 3  
  *
 4  
  * Licensed under the Educational Community License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  * http://www.opensource.org/licenses/ecl2.php
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 package org.kuali.rice.ken.util;
 17  
 
 18  
 import org.apache.commons.lang.StringUtils;
 19  
 import org.apache.log4j.Logger;
 20  
 import org.kuali.rice.core.api.config.property.ConfigContext;
 21  
 import org.kuali.rice.core.framework.persistence.dao.GenericDao;
 22  
 import org.kuali.rice.ken.bo.Notification;
 23  
 import org.kuali.rice.ken.bo.NotificationChannel;
 24  
 import org.kuali.rice.ken.bo.NotificationContentType;
 25  
 import org.kuali.rice.ken.bo.NotificationPriority;
 26  
 import org.kuali.rice.ken.bo.NotificationProducer;
 27  
 import org.kuali.rice.ken.bo.NotificationRecipient;
 28  
 import org.kuali.rice.ken.bo.NotificationSender;
 29  
 import org.kuali.rice.ken.service.NotificationContentTypeService;
 30  
 import org.w3c.dom.Document;
 31  
 import org.w3c.dom.Element;
 32  
 import org.w3c.dom.Node;
 33  
 import org.w3c.dom.NodeList;
 34  
 import org.xml.sax.EntityResolver;
 35  
 import org.xml.sax.ErrorHandler;
 36  
 import org.xml.sax.InputSource;
 37  
 import org.xml.sax.SAXException;
 38  
 import org.xml.sax.SAXParseException;
 39  
 
 40  
 import javax.xml.namespace.NamespaceContext;
 41  
 import javax.xml.parsers.DocumentBuilder;
 42  
 import javax.xml.parsers.DocumentBuilderFactory;
 43  
 import javax.xml.parsers.ParserConfigurationException;
 44  
 import javax.xml.transform.stream.StreamSource;
 45  
 import java.io.IOException;
 46  
 import java.sql.Timestamp;
 47  
 import java.text.DateFormat;
 48  
 import java.text.ParseException;
 49  
 import java.text.SimpleDateFormat;
 50  
 import java.util.ArrayList;
 51  
 import java.util.Collections;
 52  
 import java.util.Date;
 53  
 import java.util.HashMap;
 54  
 import java.util.Map;
 55  
 import java.util.TimeZone;
 56  
 
 57  
 /**
 58  
  * A general Utility class for the Notification system.
 59  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 60  
  */
 61  0
 public final class Util {
 62  0
     private static final Logger LOG = Logger.getLogger(Util.class);
 63  
     
 64  
     public static final java.lang.String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
 65  
     public static final java.lang.String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";
 66  
 
 67  0
     public static final NamespaceContext NOTIFICATION_NAMESPACE_CONTEXT
 68  
         = new ConfiguredNamespaceContext(Collections.singletonMap("nreq", "ns:notification/NotificationRequest"));
 69  
 
 70  
     private static final String ZULU_FORMAT = "yyyy-MM-dd'T'HH:mm:ss";
 71  0
     private static final TimeZone ZULU_TZ = TimeZone.getTimeZone("UTC");
 72  
 
 73  
     private static final String CURR_TZ_FORMAT = "MM/dd/yyyy hh:mm a";
 74  
     
 75  0
         private Util() {
 76  0
                 throw new UnsupportedOperationException("do not call");
 77  
         }
 78  
 
 79  
     /**
 80  
      * @return the name of the user configured to be the Notification system user
 81  
      */
 82  
     public static String getNotificationSystemUser() {
 83  0
         String system_user = ConfigContext.getCurrentContextConfig().getProperty(NotificationConstants.KEW_CONSTANTS.NOTIFICATION_SYSTEM_USER_PARAM);
 84  0
         if (system_user == null) {
 85  0
             system_user = NotificationConstants.KEW_CONSTANTS.NOTIFICATION_SYSTEM_USER;
 86  
         }
 87  0
         return system_user;
 88  
     }
 89  
 
 90  
     /**
 91  
      * Parses a date/time string under XSD dateTime type syntax
 92  
      * @see #ZULU_FORMAT
 93  
      * @param dateTimeString an XSD dateTime-formatted String
 94  
      * @return a Date representing the time value of the String parameter 
 95  
      * @throws ParseException if an error occurs during parsing 
 96  
      */
 97  
     public static Date parseXSDDateTime(String dateTimeString) throws ParseException {
 98  0
             return createZulu().parse(dateTimeString);
 99  
     }
 100  
 
 101  
     /**
 102  
      * Formats a Date into XSD dateTime format
 103  
      * @param d the date value to format
 104  
      * @return date value formatted into XSD dateTime format
 105  
      */
 106  
     public static String toXSDDateTimeString(Date d) {
 107  0
         return createZulu().format(d);
 108  
     }
 109  
     
 110  
     /**
 111  
      * Returns the current date formatted for the UI
 112  
      * @return the current date formatted for the UI
 113  
      */
 114  
     public static String getCurrentDateTime() {
 115  0
         return toUIDateTimeString(new Date());
 116  
     }
 117  
     
 118  
     /**
 119  
      * Returns the specified date formatted for the UI
 120  
      * @return the specified date formatted for the UI
 121  
      */
 122  
     public static String toUIDateTimeString(Date d) {
 123  0
         return createCurrTz().format(d);
 124  
     }
 125  
 
 126  
     /**
 127  
      * Parses the string in UI date time format
 128  
      * @return the date parsed from UI date time format
 129  
      */
 130  
     public static Date parseUIDateTime(String s) throws ParseException {
 131  0
         return createCurrTz().parse(s);
 132  
     }
 133  
 
 134  
     /**
 135  
      * Returns a compound NamespaceContext that defers to the preconfigured notification namespace context
 136  
      * first, then delegates to the document prefix/namespace definitions second.
 137  
      * @param doc the Document to use for prefix/namespace resolution
 138  
      * @return  compound NamespaceContext
 139  
      */
 140  
     public static NamespaceContext getNotificationNamespaceContext(Document doc) {
 141  0
         return new CompoundNamespaceContext(NOTIFICATION_NAMESPACE_CONTEXT, new DocumentNamespaceContext(doc));
 142  
     }
 143  
 
 144  
     /**
 145  
      * Returns an EntityResolver to resolve XML entities (namely schema resources) in the notification system
 146  
      * @param notificationContentTypeService the NotificationContentTypeService
 147  
      * @return an EntityResolver to resolve XML entities (namely schema resources) in the notification system
 148  
      */
 149  
     public static EntityResolver getNotificationEntityResolver(NotificationContentTypeService notificationContentTypeService) {
 150  0
         return new CompoundEntityResolver(new ClassLoaderEntityResolver("schema", "notification"),
 151  
                                           new ContentTypeEntityResolver(notificationContentTypeService));
 152  
     }
 153  
 
 154  
     /**
 155  
      * transformContent - transforms xml content in notification to a string
 156  
      * using the xsl in the datastore for a given documentType
 157  
      * @param notification
 158  
      * @return
 159  
      */
 160  
     public static String transformContent(Notification notification) {
 161  0
         NotificationContentType contentType = notification.getContentType();
 162  0
         String xsl = contentType.getXsl();
 163  
         
 164  0
         LOG.debug("xsl: "+xsl);
 165  
         
 166  0
         XslSourceResolver xslresolver = new XslSourceResolver();
 167  
         //StreamSource xslsource = xslresolver.resolveXslFromFile(xslpath);
 168  0
         StreamSource xslsource = xslresolver.resolveXslFromString(xsl);
 169  0
         String content = notification.getContent();
 170  0
         LOG.debug("xslsource:"+xslsource.toString());
 171  
         
 172  0
         String contenthtml = new String();
 173  
         try {
 174  0
           ContentTransformer transformer = new ContentTransformer(xslsource);
 175  0
           contenthtml = transformer.transform(content);
 176  0
           LOG.debug("html: "+contenthtml);
 177  0
         } catch (IOException ex) {
 178  0
             LOG.error("IOException transforming document",ex);
 179  0
         } catch (Exception ex) {
 180  0
             LOG.error("Exception transforming document",ex);
 181  0
         } 
 182  0
         return contenthtml;
 183  
     }
 184  
 
 185  
     /**
 186  
      * This method uses DOM to parse the input source of XML.
 187  
      * @param source the input source
 188  
      * @param validate whether to turn on validation
 189  
      * @param namespaceAware whether to turn on namespace awareness
 190  
      * @return Document the parsed (possibly validated) document
 191  
      * @throws ParserConfigurationException
 192  
      * @throws IOException
 193  
      * @throws SAXException
 194  
      */
 195  
     public static Document parse(final InputSource source, boolean validate, boolean namespaceAware, EntityResolver entityResolver) throws ParserConfigurationException, IOException, SAXException {
 196  
         // TODO: optimize this
 197  0
         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
 198  0
         dbf.setValidating(validate);
 199  0
         dbf.setNamespaceAware(namespaceAware);
 200  0
         dbf.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
 201  0
         DocumentBuilder db = dbf.newDocumentBuilder();
 202  0
         if (entityResolver != null) {
 203  0
             db.setEntityResolver(entityResolver);
 204  
         }
 205  0
         db.setErrorHandler(new ErrorHandler() {
 206  
             public void warning(SAXParseException se) {
 207  0
                 LOG.warn("Warning parsing xml doc " + source, se);
 208  0
             }
 209  
             public void error(SAXParseException se) throws SAXException {
 210  0
                 LOG.error("Error parsing xml doc " + source, se);
 211  0
                 throw se;
 212  
             }
 213  
             public void fatalError(SAXParseException se) throws SAXException {
 214  0
                 LOG.error("Fatal error parsing xml doc " + source, se);
 215  0
                 throw se;
 216  
             }
 217  
         });
 218  0
         return db.parse(source);
 219  
     }
 220  
 
 221  
     /**
 222  
      * This method uses DOM to parse the input source of XML, supplying a notification-system-specific
 223  
      * entity resolver.
 224  
      * @param source the input source
 225  
      * @param validate whether to turn on validation
 226  
      * @param namespaceAware whether to turn on namespace awareness
 227  
      * @return Document the parsed (possibly validated) document
 228  
      * @throws ParserConfigurationException
 229  
      * @throws IOException
 230  
      * @throws SAXException
 231  
      */
 232  
     public static Document parseWithNotificationEntityResolver(final InputSource source, boolean validate, boolean namespaceAware, NotificationContentTypeService notificationContentTypeService) throws ParserConfigurationException, IOException, SAXException {
 233  0
         return parse(source, validate, namespaceAware, getNotificationEntityResolver(notificationContentTypeService));
 234  
     }
 235  
 
 236  
     /**
 237  
      * Returns a node child with the specified tag name of the specified parent node,
 238  
      * or null if no such child node is found. 
 239  
      * @param parent the parent node
 240  
      * @param name the name of the child node
 241  
      * @return child node if found, null otherwise
 242  
      */
 243  
     public static Element getChildElement(Node parent, String name) {
 244  0
         NodeList childList = parent.getChildNodes();
 245  0
         for (int i = 0; i < childList.getLength(); i++) {
 246  0
             Node node = childList.item(i);
 247  
             // we must test against NodeName, not just LocalName
 248  
             // LocalName seems to be null - I am guessing this is because
 249  
             // the DocumentBuilderFactory is not "namespace aware"
 250  
             // although I would have expected LocalName to default to
 251  
             // NodeName
 252  0
             if (node.getNodeType() == Node.ELEMENT_NODE
 253  
                 && (name.equals(node.getLocalName())
 254  
                    || name.equals(node.getNodeName()))) {
 255  0
                 return (Element) node;
 256  
             }
 257  
         }
 258  0
         return null;
 259  
     }
 260  
     
 261  
     /**
 262  
      * This method will clone a given Notification object, one level deep, returning a fresh new instance 
 263  
      * without any references.
 264  
      * @param notification the object to clone
 265  
      * @return Notification a fresh instance
 266  
      */
 267  
     public static final Notification cloneNotificationWithoutObjectReferences(Notification notification) {
 268  0
         Notification clone = new Notification();
 269  
         
 270  
         // handle simple data types first
 271  0
         if(notification.getCreationDateTime() != null) {
 272  0
             clone.setCreationDateTime(new Timestamp(notification.getCreationDateTime().getTime()));
 273  
         }
 274  0
         if(notification.getAutoRemoveDateTime() != null) {
 275  0
             clone.setAutoRemoveDateTime(new Timestamp(notification.getAutoRemoveDateTime().getTime()));
 276  
         }
 277  0
         clone.setContent(new String(notification.getContent()));
 278  0
         clone.setDeliveryType(new String(notification.getDeliveryType()));
 279  0
         if(notification.getId() != null) {
 280  0
             clone.setId(new Long(notification.getId()));
 281  
         }
 282  0
         clone.setProcessingFlag(new String(notification.getProcessingFlag()));
 283  0
         if(notification.getSendDateTime() != null) {
 284  0
             clone.setSendDateTime(new Timestamp(notification.getSendDateTime().getTime()));
 285  
         }
 286  
         
 287  0
         clone.setTitle(notification.getTitle());
 288  
         
 289  
         // now take care of the channel
 290  0
         NotificationChannel channel = new NotificationChannel();
 291  0
         channel.setId(new Long(notification.getChannel().getId()));
 292  0
         channel.setName(new String(notification.getChannel().getName()));
 293  0
         channel.setDescription(new String(notification.getChannel().getDescription()));
 294  0
         channel.setSubscribable(new Boolean(notification.getChannel().isSubscribable()).booleanValue());
 295  0
         clone.setChannel(channel);
 296  
         
 297  
         // handle the content type
 298  0
         NotificationContentType contentType = new NotificationContentType();
 299  0
         contentType.setId(new Long(notification.getContentType().getId()));
 300  0
         contentType.setDescription(new String(notification.getContentType().getDescription()));
 301  0
         contentType.setName(new String(notification.getContentType().getName()));
 302  0
         contentType.setNamespace(new String(notification.getContentType().getNamespace()));
 303  0
         clone.setContentType(contentType);
 304  
         
 305  
         // take care of the prioirity
 306  0
         NotificationPriority priority = new NotificationPriority();
 307  0
         priority.setDescription(new String(notification.getPriority().getDescription()));
 308  0
         priority.setId(new Long(notification.getPriority().getId()));
 309  0
         priority.setName(new String(notification.getPriority().getName()));
 310  0
         priority.setOrder(new Integer(notification.getPriority().getOrder()));
 311  0
         clone.setPriority(priority);
 312  
         
 313  
         // take care of the producer
 314  0
         NotificationProducer producer = new NotificationProducer();
 315  0
         producer.setDescription(new String(notification.getProducer().getDescription()));
 316  0
         producer.setId(new Long(notification.getProducer().getId()));
 317  0
         producer.setName(new String(notification.getProducer().getName()));
 318  0
         producer.setContactInfo(new String(notification.getProducer().getContactInfo()));
 319  0
         clone.setProducer(producer);
 320  
         
 321  
         // process the list of recipients now
 322  0
         ArrayList<NotificationRecipient> recipients = new ArrayList<NotificationRecipient>();
 323  0
         for(int i = 0; i < notification.getRecipients().size(); i++) {
 324  0
             NotificationRecipient recipient = notification.getRecipient(i);
 325  0
             NotificationRecipient cloneRecipient = new NotificationRecipient();
 326  0
             cloneRecipient.setRecipientId(new String(recipient.getRecipientId()));
 327  0
             cloneRecipient.setRecipientType(new String(recipient.getRecipientType()));
 328  
             
 329  0
             recipients.add(cloneRecipient);
 330  
         }
 331  0
         clone.setRecipients(recipients);
 332  
         
 333  
         // process the list of senders now
 334  0
         ArrayList<NotificationSender> senders = new ArrayList<NotificationSender>();
 335  0
         for(int i = 0; i < notification.getSenders().size(); i++) {
 336  0
             NotificationSender sender = notification.getSender(i);
 337  0
             NotificationSender cloneSender = new NotificationSender();
 338  0
             cloneSender.setSenderName(new String(sender.getSenderName()));
 339  
             
 340  0
             senders.add(cloneSender);
 341  
         }
 342  0
         clone.setSenders(senders);
 343  
         
 344  0
         return clone;
 345  
     }
 346  
     
 347  
     /**
 348  
      * This method generically retrieves a reference to foreign key objects that are part of the content, to get 
 349  
      * at the reference objects' pk fields so that those values can be used to store the notification with proper 
 350  
      * foreign key relationships in the database.
 351  
      * @param <T>
 352  
      * @param fieldName
 353  
      * @param keyName
 354  
      * @param keyValue
 355  
      * @param clazz
 356  
      * @param boDao
 357  
      * @return T
 358  
      * @throws IllegalArgumentException
 359  
      */
 360  
     public static <T> T retrieveFieldReference(String fieldName, String keyName, String keyValue, Class clazz, GenericDao boDao) throws IllegalArgumentException {
 361  0
         LOG.debug(fieldName + " key value: " + keyValue);
 362  0
         if (StringUtils.isBlank(keyValue)) {
 363  0
             throw new IllegalArgumentException(fieldName + " must be specified in notification");
 364  
         }
 365  0
         Map<String, Object> keys = new HashMap<String, Object>(1);
 366  0
         keys.put(keyName, keyValue);
 367  0
         T reference = (T) boDao.findByPrimaryKey(clazz, keys);
 368  0
         if (reference == null) {
 369  0
             throw new IllegalArgumentException(fieldName + " '" + keyValue + "' not found");
 370  
         }
 371  0
         return reference;
 372  
     }
 373  
 
 374  
     /** date formats are not thread safe so creating a new one each time it is needed. */
 375  
     private static DateFormat createZulu() {
 376  0
         final DateFormat df = new SimpleDateFormat(ZULU_FORMAT);
 377  0
         df.setTimeZone(ZULU_TZ);
 378  0
         return df;
 379  
     }
 380  
 
 381  
     /** date formats are not thread safe so creating a new one each time it is needed. */
 382  
     private static DateFormat createCurrTz() {
 383  0
         return new SimpleDateFormat(CURR_TZ_FORMAT);
 384  
     }
 385  
 }