]> git.aero2k.de Git - tmp/jakarta-migration.git/commitdiff
CSPACE-2408,CSPACE-2418: Changed datatypes for three calendar date fields in Movement...
authorAron Roberts <aron@socrates.berkeley.edu>
Wed, 14 Jul 2010 03:49:37 +0000 (03:49 +0000)
committerAron Roberts <aron@socrates.berkeley.edu>
Wed, 14 Jul 2010 03:49:37 +0000 (03:49 +0000)
services/movement/3rdparty/nuxeo-platform-cs-movement/src/main/resources/schemas/movements_common.xsd
services/movement/client/pom.xml
services/movement/client/src/main/java/org/collectionspace/services/client/MovementClientDateTimeUtils.java [new file with mode: 0644]
services/movement/client/src/test/java/org/collectionspace/services/client/test/MovementServiceTest.java
services/movement/service/src/main/java/org/collectionspace/services/movement/nuxeo/MovementDocumentModelHandler.java
services/movement/service/src/main/java/org/collectionspace/services/movement/nuxeo/MovementServiceDateTimeUtils.java [new file with mode: 0644]

index 693ec14c8862e8193738b6179e970a94e5645b79..5cdf43fcbce79dfc4bff326710bd4f0e13313f45 100644 (file)
@@ -24,7 +24,7 @@
     <xs:element name="currentLocation" type="xs:string"/>\r
     <xs:element name="currentLocationFitness" type="xs:string"/>\r
     <xs:element name="currentLocationNote" type="xs:string"/>\r
-    <xs:element name="locationDate" type="xs:string"/>\r
+    <xs:element name="locationDate" type="xs:dateTime"/>\r
     <xs:element name="normalLocation" type="xs:string"/>\r
     \r
     <!--  Movement Information Group -->\r
@@ -38,8 +38,8 @@
     </xs:element>\r
     <xs:element name="movementNote" type="xs:string"/>\r
     <xs:element name="movementReferenceNumber" type="xs:string"/>\r
-    <xs:element name="plannedRemovalDate" type="xs:string"/>\r
-    <xs:element name="removalDate" type="xs:string"/>\r
+    <xs:element name="plannedRemovalDate" type="xs:dateTime"/>\r
+    <xs:element name="removalDate" type="xs:dateTime"/>\r
     <xs:element name="reasonForMove" type="xs:string"/>\r
     \r
 </xs:schema>\r
index 8b6fe1fbf9eee81d388949ac21a9a57e85293fe5..bbc2e396c8e98675c46a1726b8fe76099fed0bac 100644 (file)
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
-            <scope>test</scope>
+            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-log4j12</artifactId>
-            <scope>test</scope>
+            <scope>provided</scope>
         </dependency>
 <!-- CollectionSpace dependencies -->
         <dependency>
diff --git a/services/movement/client/src/main/java/org/collectionspace/services/client/MovementClientDateTimeUtils.java b/services/movement/client/src/main/java/org/collectionspace/services/client/MovementClientDateTimeUtils.java
new file mode 100644 (file)
index 0000000..8fc7ee2
--- /dev/null
@@ -0,0 +1,216 @@
+/**    
+ * This document is a part of the source code and related artifacts
+ * for CollectionSpace, an open source collections management system
+ * for museums and related institutions:
+ *
+ * http://www.collectionspace.org
+ * http://wiki.collectionspace.org
+ *
+ * Copyright (c) 2009 Regents of the University of California
+ *
+ * Licensed under the Educational Community License (ECL), Version 2.0.
+ * You may not use this file except in compliance with this License.
+ *
+ * You may obtain a copy of the ECL 2.0 License at
+ * https://source.collectionspace.org/collection-space/LICENSE.txt
+ */
+package org.collectionspace.services.client;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+
+import javax.xml.datatype.DatatypeConfigurationException;
+import javax.xml.datatype.DatatypeFactory;
+import javax.xml.datatype.XMLGregorianCalendar;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * MovementClientDateTimeUtils.java
+ *
+ * $LastChangedRevision: 2107 $
+ * $LastChangedDate: 2010-05-17 18:22:27 -0700 (Mon, 17 May 2010) $
+ *
+ */
+public class MovementClientDateTimeUtils {
+
+    private static final Logger logger =
+      LoggerFactory.getLogger(MovementClientDateTimeUtils.class);
+
+    final static String UTC_TIMEZONE_IDENTIFIER = "UTC";
+    final static String ISO_8601_UTC_TIMESTAMP_PATTERN = "yyyy-MM-dd'T'HH:mm:ss'Z'";
+
+    // FIXME The methods below are not specific to the Movement service
+    // or its client code.
+    //
+    // At present, they may redundantly be included in or referenced from
+    // several classes in the Movement service module, in its 'service'
+    // and/or 'client' sub-modules.
+    //
+    // However, these methods, and any associated constants and imports
+    // above, should instead be moved to the Date and Time service or
+    // into another common package, where they can be shared by multiple services.
+
+   /**
+    * Returns the default time zone.
+    *
+    * @return The default time zone
+    */
+    public static TimeZone defaultTimeZone() {
+        return TimeZone.getDefault();
+    }
+
+   /**
+    * Returns a calendar date, representing the current date and time instance
+    * in the default time zone.
+    *
+    * @return The current date and time instance in the default time zone
+    */
+    public static GregorianCalendar currentDateAndTime() {
+        return currentDateAndTime(defaultTimeZone());
+    }
+
+   /**
+    * Returns the UTC time zone.
+    *
+    * @return The UTC time zone.  Defaults to the closely-related GMT time zone,
+    *         if for some reason the UTC time zone identifier cannot be understood.
+    */
+    public static TimeZone UTCTimeZone() {
+        return TimeZone.getTimeZone(UTC_TIMEZONE_IDENTIFIER);
+    }
+
+   /**
+    * Returns a calendar date, representing the current date and time instance
+    * in the UTC time zone.
+    *
+    * @return The current date and time instance in the UTC time zone.
+    */
+    public static GregorianCalendar currentDateAndTimeUTC() {
+        return currentDateAndTime(UTCTimeZone());
+    }
+
+   /**
+    * Returns a calendar date, representing the current date and time instance
+    * in the specified time zone.
+    *
+    * @return The current date and time instance in the specified time zone.
+    *         If the time zone is null, will return the current time and
+    *         date in the time zone intrinsic to a new Calendar instance.
+    */
+    public static GregorianCalendar currentDateAndTime(TimeZone tz) {
+        GregorianCalendar gcal = new GregorianCalendar();
+        if (tz != null) {
+            gcal.setTimeZone(tz);
+        }
+        Date now = new Date();
+        gcal.setTime(now);
+        return gcal;
+    }
+
+   /**
+    * Returns a String representing the current date and time instance.
+    * in the UTC time zone, formatted as an ISO 8601 timestamp.
+    *
+    * @return A String representing the current date and time instance.
+    */
+    public static String timestampUTC() {
+        return formatAsISO8601Timestamp(currentDateAndTime(UTCTimeZone()));
+    }
+
+   /**
+    * Returns a representation of a calendar date and time instance,
+    * as an ISO 8601-formatted timestamp in the UTC time zone.
+    *
+    * @param cal A calendar date and time instance
+    *
+    * @return    A representation of that calendar date and time instance,
+    *            as an ISO 8601-formatted timestamp in the UTC time zone.
+    */
+    public static String formatAsISO8601Timestamp(GregorianCalendar cal) {
+        return formatCalendarDate(cal, UTCTimeZone(), ISO8601TimestampFormatter());
+    }
+
+   /**
+    * Formats a provided calendar date using a provided date formatter,
+    * in the default system time zone.
+    *
+    * @param date  A calendar date to format.
+    * @param df    A date formatter to apply.
+    *
+    * @return      A formatted date string, or the empty string
+    *              if one or more of the parameter values were invalid.
+    */
+    public static String formatCalendarDate(GregorianCalendar gcal, DateFormat df) {
+        return formatCalendarDate(gcal, TimeZone.getDefault(), df);
+    }
+
+   /**
+    * Formats a provided calendar date using a provided date formatter,
+    * in a provided time zone.
+    *
+    * @param date  A calendar date to format.
+    * @param tz    The time zone qualifier for the calendar date to format.
+    * @param df    A date formatter to apply.
+    *
+    * @return      A formatted date string, or the empty string
+    *              if one or more of the parameter values were invalid.
+    */
+    public static String formatCalendarDate(GregorianCalendar gcal, TimeZone tz, DateFormat df) {
+        String formattedDate = "";
+        if (gcal == null) {
+            logger.warn("Null calendar date was provided when a non-null calendar date was required.");
+            return formattedDate;
+        }
+        if (tz == null) {
+            logger.warn("Null time zone was provided when a non-null time zone was required.");
+            return formattedDate;
+        }
+        if (df == null) {
+            logger.warn("Null date formatter was provided when a non-null date formatter was required.");
+            return formattedDate;
+        }
+        gcal.setTimeZone(tz);
+        Date date = gcal.getTime();
+        df.setTimeZone(tz);
+        formattedDate = df.format(date);
+        return formattedDate;
+    }
+
+   /**
+    * Returns a date formatter for an ISO 8601 timestamp pattern.
+    *
+    * @return  A date formatter for an ISO 8601 timestamp pattern.
+    *          This pattern is specified as a class constant above.
+    */
+    public static DateFormat ISO8601TimestampFormatter() {
+        return getDateFormatter(ISO_8601_UTC_TIMESTAMP_PATTERN);
+    }
+
+   /**
+    * Returns a date formatter for a provided date or date/time pattern.
+    *
+    * @param pattern  A date or date/time pattern.
+    *
+    * @return         A date formatter using that pattern, or null
+    *                 if the pattern was null, empty, or invalid.
+    */
+    public static DateFormat getDateFormatter(String pattern) {
+        DateFormat df = null;
+        if (pattern == null || pattern.trim().isEmpty()) {
+            logger.warn("Null or empty date pattern string was provided " +
+                "when a non-null, non-empty date pattern string was required.");
+            return df;
+        }
+        try {
+            df = new SimpleDateFormat(pattern);
+        } catch (IllegalArgumentException iae) {
+            logger.warn("Invalid date pattern string: " + pattern);
+        }
+        return df;
+    }
+}
index bebc7bc5ed64d42963f58650395bb19ad8953bca..1ad9bd8d06111df94de9f53b7c29da71484f5316 100644 (file)
@@ -33,6 +33,7 @@ import javax.ws.rs.core.Response;
 
 import org.collectionspace.services.client.CollectionSpaceClient;
 import org.collectionspace.services.client.MovementClient;
+import org.collectionspace.services.client.MovementClientDateTimeUtils;
 import org.collectionspace.services.jaxb.AbstractCommonList;
 import org.collectionspace.services.movement.MovementsCommon;
 import org.collectionspace.services.movement.MovementsCommonList;
@@ -732,12 +733,13 @@ public class MovementServiceTest extends AbstractServiceTestImpl {
      */
     private MultipartOutput createInstance(String movementReferenceNumber) {
         MovementsCommon movement = new MovementsCommon();
+        String timestampUTC = MovementClientDateTimeUtils.timestampUTC();
         // FIXME: Values of currentLocation, normalLocation,
         // and movementContact should be refNames.
         movement.setCurrentLocation("currentLocation value");
         movement.setCurrentLocationFitness("currentLocationFitness value");
         movement.setCurrentLocationNote("currentLocationNote value");
-        movement.setLocationDate(timestampUTC());
+        movement.setLocationDate(timestampUTC);
         movement.setNormalLocation("normalLocation value");
         movement.setMovementContact("movementContact value");
         MovementMethodsList movementMethodsList = new MovementMethodsList();
@@ -750,8 +752,8 @@ public class MovementServiceTest extends AbstractServiceTestImpl {
         movement.setMovementMethods(movementMethodsList);
         movement.setMovementNote("movementNote value");
         movement.setMovementReferenceNumber(movementReferenceNumber);
-        movement.setPlannedRemovalDate("plannedRemovalDate value");
-        movement.setRemovalDate("removalDate value");
+        movement.setPlannedRemovalDate(timestampUTC);
+        movement.setRemovalDate(timestampUTC);
         movement.setReasonForMove("reasonForMove value");
         MultipartOutput multipart = new MultipartOutput();
         OutputPart commonPart =
index c7cf06b04d9f62cf744ee08601fe1d41f88ae350..f06a615de98380d822c8d0aa4a4c4bd12c718029 100644 (file)
  */
 package org.collectionspace.services.movement.nuxeo;
 
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
 
 import org.collectionspace.services.MovementJAXBSchema;
 import org.collectionspace.services.common.document.DocumentWrapper;
+import org.collectionspace.services.common.service.ObjectPartType;
 import org.collectionspace.services.movement.MovementsCommon;
 import org.collectionspace.services.movement.MovementsCommonList;
 import org.collectionspace.services.movement.MovementsCommonList.MovementListItem;
@@ -46,6 +52,10 @@ public class MovementDocumentModelHandler
 
     /** The logger. */
     private final Logger logger = LoggerFactory.getLogger(MovementDocumentModelHandler.class);
+
+    private static final String COMMON_PART_LABEL = "movements_common";
+
+    private static final ArrayList<String> DATE_TIME_FIELDS = dateTimeFields();
     
     /** The Movement. */
     private MovementsCommon Movement;
@@ -94,6 +104,29 @@ public class MovementDocumentModelHandler
         this.MovementList = MovementList;
     }
 
+    /* (non-Javadoc)
+     * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#extractPart(org.nuxeo.ecm.core.api.DocumentModel, java.lang.String, org.collectionspace.services.common.service.ObjectPartType)
+     */
+    @Override
+    protected Map<String, Object> extractPart(DocumentModel docModel, String schema, ObjectPartType partMeta)
+            throws Exception {
+       Map<String, Object> unQObjectProperties = super.extractPart(docModel, schema, partMeta);
+
+       // For each dateTime field in the common part, return an
+        // appropriately formatted representation of its value.
+       if (partMeta.getLabel().equalsIgnoreCase(COMMON_PART_LABEL)) {
+            for(Entry<String, Object> entry : unQObjectProperties.entrySet()){
+                if (isDateTimeType(entry)) {
+                    entry.setValue(
+                        MovementServiceDateTimeUtils.formatAsISO8601Timestamp(
+                            (GregorianCalendar) entry.getValue()));
+                }
+            }
+       }
+
+        return unQObjectProperties;
+    }
+
     /**
      * Extract common part.
      *
@@ -136,8 +169,9 @@ public class MovementDocumentModelHandler
             MovementListItem ilistItem = new MovementListItem();
             ilistItem.setMovementReferenceNumber((String) docModel.getProperty(getServiceContext().getCommonPartLabel(),
                     MovementJAXBSchema.MOVEMENT_REFERENCE_NUMBER));
-            ilistItem.setLocationDate((String) docModel.getProperty(getServiceContext().getCommonPartLabel(),
-                    MovementJAXBSchema.LOCATION_DATE));
+            GregorianCalendar gcal = (GregorianCalendar) docModel.getProperty(getServiceContext().getCommonPartLabel(),
+                    MovementJAXBSchema.LOCATION_DATE);
+            ilistItem.setLocationDate(MovementServiceDateTimeUtils.formatAsISO8601Timestamp(gcal));
             String id = NuxeoUtils.extractId(docModel.getPathAsString());
             ilistItem.setUri(getServiceContextPath() + id);
             ilistItem.setCsid(id);
@@ -157,6 +191,46 @@ public class MovementDocumentModelHandler
     public String getQProperty(String prop) {
         return MovementConstants.NUXEO_SCHEMA_NAME + ":" + prop;
     }
+
+    private boolean isDateTimeType(Entry<String, Object> entry) {
+        boolean isDateTimeType = false;
+
+        // Approach 1: Check the name of this property against a list of
+        // dateTime field names.
+        if (DATE_TIME_FIELDS.contains(entry.getKey())){
+           isDateTimeType = true;
+        }
+
+        // Approach 2: Check the data type of this property's value.
+        /*
+        if (entry.getValue() instanceof Calendar) {
+            isDateTimeType = true;
+        }
+         *
+         */
+
+        return isDateTimeType;
+    }
+
+    /**
+     * Returns a list of the names of dateTime fields (e.g. fields whose
+     * XML Schema datatype is xs:dateTime).
+     *
+     * @return A list of names of dateTime fields.
+     */
+    private static ArrayList<String> dateTimeFields() {
+        // FIXME Rather than hard-coding directly here,
+        // identify these fields from configuration, such as:
+        // * Metadata returned from Nuxeo, if available.
+        // * Examination of the XSD schema for this document type.
+        // * External configuration (e.g. date fields as tenant bindings props, via
+        //   org.collectionspace.services.common.context.ServiceBindingUtils)
+        ArrayList<String> dateTimeTypeFields = new ArrayList();
+        dateTimeTypeFields.add(MovementJAXBSchema.LOCATION_DATE);
+        dateTimeTypeFields.add(MovementJAXBSchema.PLANNED_REMOVAL_DATE);
+        dateTimeTypeFields.add(MovementJAXBSchema.REMOVAL_DATE);
+        return dateTimeTypeFields;
+    }
  
 }
 
diff --git a/services/movement/service/src/main/java/org/collectionspace/services/movement/nuxeo/MovementServiceDateTimeUtils.java b/services/movement/service/src/main/java/org/collectionspace/services/movement/nuxeo/MovementServiceDateTimeUtils.java
new file mode 100644 (file)
index 0000000..7877e21
--- /dev/null
@@ -0,0 +1,194 @@
+/**    
+ * This document is a part of the source code and related artifacts
+ * for CollectionSpace, an open source collections management system
+ * for museums and related institutions:
+ *
+ * http://www.collectionspace.org
+ * http://wiki.collectionspace.org
+ *
+ * Copyright (c) 2009 Regents of the University of California
+ *
+ * Licensed under the Educational Community License (ECL), Version 2.0.
+ * You may not use this file except in compliance with this License.
+ *
+ * You may obtain a copy of the ECL 2.0 License at
+ * https://source.collectionspace.org/collection-space/LICENSE.txt
+ */
+package org.collectionspace.services.movement.nuxeo;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * MovementClientDateTimeUtils.java
+ *
+ * $LastChangedRevision: 2107 $
+ * $LastChangedDate: 2010-05-17 18:22:27 -0700 (Mon, 17 May 2010) $
+ *
+ */
+public class MovementServiceDateTimeUtils {
+
+    private static final Logger logger =
+      LoggerFactory.getLogger(MovementServiceDateTimeUtils.class);
+
+    final static String UTC_TIMEZONE_IDENTIFIER = "UTC";
+    final static String ISO_8601_UTC_TIMESTAMP_PATTERN = "yyyy-MM-dd'T'HH:mm:ss'Z'";
+
+    // FIXME The methods below are not specific to the Movement service
+    // or its client code.
+    //
+    // At present, they may redundantly be included in or referenced from
+    // several classes in the Movement service module, in its 'service'
+    // and/or 'client' sub-modules.
+    //
+    // However, these methods, and any associated constants and imports
+    // above, should instead be moved to the Date and Time service or
+    // into another common package, where they can be shared by multiple services.
+
+   /**
+    * Returns the UTC time zone.
+    *
+    * @return The UTC time zone.  Defaults to the closely-related GMT time zone,
+    *         if for some reason the UTC time zone identifier cannot be understood.
+    */
+    public static TimeZone UTCTimeZone() {
+        return TimeZone.getTimeZone(UTC_TIMEZONE_IDENTIFIER);
+    }
+
+   /**
+    * Returns a calendar date, representing the current date and time instance
+    * in the UTC time zone.
+    *
+    * @return The current date and time instance in the UTC time zone.
+    */
+    public static GregorianCalendar currentDateAndTimeUTC() {
+        return currentDateAndTime(UTCTimeZone());
+    }
+
+   /**
+    * Returns a calendar date, representing the current date and time instance
+    * in the specified time zone.
+    *
+    * @return The current date and time instance in the specified time zone.
+    *         If the time zone is null, will return the current time and
+    *         date in the time zone intrinsic to a new Calendar instance.
+    */
+    public static GregorianCalendar currentDateAndTime(TimeZone tz) {
+        GregorianCalendar gcal = new GregorianCalendar();
+        if (tz != null) {
+            gcal.setTimeZone(tz);
+        }
+        Date now = new Date();
+        gcal.setTime(now);
+        return gcal;
+    }
+
+   /**
+    * Returns a String representing the current date and time instance.
+    * in the UTC time zone, formatted as an ISO 8601 timestamp.
+    *
+    * @return A String representing the current date and time instance.
+    */
+    public static String timestampUTC() {
+        return formatAsISO8601Timestamp(currentDateAndTime(UTCTimeZone()));
+    }
+
+   /**
+    * Returns a representation of a calendar date and time instance,
+    * as an ISO 8601-formatted timestamp in the UTC time zone.
+    *
+    * @param cal A calendar date and time instance
+    *
+    * @return    A representation of that calendar date and time instance,
+    *            as an ISO 8601-formatted timestamp in the UTC time zone.
+    */
+    public static String formatAsISO8601Timestamp(GregorianCalendar cal) {
+        return formatCalendarDate(cal, UTCTimeZone(), ISO8601TimestampFormatter());
+    }
+
+   /**
+    * Formats a provided calendar date using a provided date formatter,
+    * in the default system time zone.
+    *
+    * @param date  A calendar date to format.
+    * @param df    A date formatter to apply.
+    *
+    * @return      A formatted date string, or the empty string
+    *              if one or more of the parameter values were invalid.
+    */
+    public static String formatCalendarDate(GregorianCalendar gcal, DateFormat df) {
+        return formatCalendarDate(gcal, TimeZone.getDefault(), df);
+    }
+
+   /**
+    * Formats a provided calendar date using a provided date formatter,
+    * in a provided time zone.
+    *
+    * @param date  A calendar date to format.
+    * @param tz    The time zone qualifier for the calendar date to format.
+    * @param df    A date formatter to apply.
+    *
+    * @return      A formatted date string, or the empty string
+    *              if one or more of the parameter values were invalid.
+    */
+    public static String formatCalendarDate(GregorianCalendar gcal, TimeZone tz, DateFormat df) {
+        String formattedDate = "";
+        if (gcal == null) {
+            logger.warn("Null calendar date was provided when a non-null calendar date was required.");
+            return formattedDate;
+        }
+        if (tz == null) {
+            logger.warn("Null time zone was provided when a non-null time zone was required.");
+            return formattedDate;
+        }
+        if (df == null) {
+            logger.warn("Null date formatter was provided when a non-null date formatter was required.");
+            return formattedDate;
+        }
+        gcal.setTimeZone(tz);
+        Date date = gcal.getTime();
+        df.setTimeZone(tz);
+        formattedDate = df.format(date);
+        return formattedDate;
+    }
+
+   /**
+    * Returns a date formatter for an ISO 8601 timestamp pattern.
+    *
+    * @return  A date formatter for an ISO 8601 timestamp pattern.
+    *          This pattern is specified as a class constant above.
+    */
+    public static DateFormat ISO8601TimestampFormatter() {
+        return getDateFormatter(ISO_8601_UTC_TIMESTAMP_PATTERN);
+    }
+
+   /**
+    * Returns a date formatter for a provided date or date/time pattern.
+    *
+    * @param pattern  A date or date/time pattern.
+    *
+    * @return         A date formatter using that pattern, or null
+    *                 if the pattern was null, empty, or invalid.
+    */
+    public static DateFormat getDateFormatter(String pattern) {
+        DateFormat df = null;
+        if (pattern == null || pattern.trim().isEmpty()) {
+            logger.warn("Null or empty date pattern string was provided " +
+                "when a non-null, non-empty date pattern string was required.");
+            return df;
+        }
+        try {
+            df = new SimpleDateFormat(pattern);
+        } catch (IllegalArgumentException iae) {
+            logger.warn("Invalid date pattern string: " + pattern);
+        }
+        return df;
+    }
+
+}