Switch time keeping to java.time interfaces 89/53189/8
authorRobert Varga <rovarga@cisco.com>
Sun, 12 Mar 2017 00:15:44 +0000 (01:15 +0100)
committerRobert Varga <rovarga@cisco.com>
Sun, 12 Mar 2017 16:00:07 +0000 (17:00 +0100)
Date-based interfaces are not thread-safe and ambiguous, Java 8
gives us java.time, which has proper domain model.

Change-Id: I6b0fa37c008a96ed6a47afc68a809570fd1848a0
Signed-off-by: Robert Varga <rovarga@cisco.com>
restconf/sal-rest-connector/src/main/java/org/opendaylight/netconf/sal/restconf/impl/RestconfImpl.java
restconf/sal-rest-connector/src/main/java/org/opendaylight/netconf/sal/streams/listeners/AbstractQueryParams.java
restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/services/impl/RestconfDataServiceImpl.java
restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/services/impl/RestconfStreamsSubscriptionServiceImpl.java
restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/RestconfStreamsConstants.java
restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/SubscribeToStreamUtil.java
restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/utils/mapping/RestconfMappingNodeUtil.java
restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ExpressionParserTest.java
restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfImplNotificationSubscribingTest.java
restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/jersey/providers/AbstractBodyReaderTest.java
restconf/sal-rest-connector/src/test/java/org/opendaylight/restconf/utils/mapping/RestconfMappingNodeUtilTest.java

index 7484a377fbfee48266dc392d80ed438adadea9b0..d28fcea107cb34af0b2bc6564cc4399b5e3e9a09 100644 (file)
@@ -19,18 +19,19 @@ import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
 import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.Futures;
 import java.net.URI;
-import java.net.URISyntaxException;
-import java.text.DateFormat;
 import java.text.ParseException;
-import java.text.SimpleDateFormat;
+import java.time.Instant;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
+import java.time.temporal.TemporalAccessor;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Date;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -70,6 +71,7 @@ import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
@@ -121,10 +123,6 @@ public class RestconfImpl implements RestconfService {
 
     private static final String SAL_REMOTE_NAMESPACE = "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote";
 
-    private BrokerFacade broker;
-
-    private ControllerContext controllerContext;
-
     private static final Logger LOG = LoggerFactory.getLogger(RestconfImpl.class);
 
     private static final DataChangeScope DEFAULT_SCOPE = DataChangeScope.BASE;
@@ -143,11 +141,23 @@ public class RestconfImpl implements RestconfService {
 
     private static final String NETCONF_BASE_PAYLOAD_NAME = "data";
 
-    private static final QName NETCONF_BASE_QNAME;
+    private static final QName NETCONF_BASE_QNAME = QName.create(QNameModule.create(URI.create(NETCONF_BASE), null),
+        NETCONF_BASE_PAYLOAD_NAME).intern();
 
     private static final QNameModule SAL_REMOTE_AUGMENT;
+    static {
+        try {
+            SAL_REMOTE_AUGMENT = QNameModule.create(NAMESPACE_EVENT_SUBSCRIPTION_AUGMENT,
+                SimpleDateFormatUtil.getRevisionFormat().parse("2014-07-08"));
+        } catch (final ParseException e) {
+            throw new ExceptionInInitializerError(e);
+        }
+    }
 
-    private static final YangInstanceIdentifier.AugmentationIdentifier SAL_REMOTE_AUG_IDENTIFIER;
+    private static final AugmentationIdentifier SAL_REMOTE_AUG_IDENTIFIER =
+            new AugmentationIdentifier(ImmutableSet.of(
+                QName.create(SAL_REMOTE_AUGMENT, "scope"), QName.create(SAL_REMOTE_AUGMENT, "datastore"),
+                QName.create(SAL_REMOTE_AUGMENT, "notification-output-type")));
 
     public static final CharSequence DATA_SUBSCR = "data-change-event-subscription";
     private static final CharSequence CREATE_DATA_SUBSCR = "create-" + DATA_SUBSCR;
@@ -155,24 +165,19 @@ public class RestconfImpl implements RestconfService {
     public static final CharSequence NOTIFICATION_STREAM = "notification-stream";
     private static final CharSequence CREATE_NOTIFICATION_STREAM = "create-" + NOTIFICATION_STREAM;
 
-    static {
-        try {
-            final Date eventSubscriptionAugRevision = SimpleDateFormatUtil.getRevisionFormat().parse("2014-07-08");
-            NETCONF_BASE_QNAME =
-                    QName.create(QNameModule.create(new URI(NETCONF_BASE), null), NETCONF_BASE_PAYLOAD_NAME);
-            SAL_REMOTE_AUGMENT = QNameModule.create(NAMESPACE_EVENT_SUBSCRIPTION_AUGMENT, eventSubscriptionAugRevision);
-            SAL_REMOTE_AUG_IDENTIFIER = new YangInstanceIdentifier.AugmentationIdentifier(Sets.newHashSet(
-                    QName.create(SAL_REMOTE_AUGMENT, "scope"), QName.create(SAL_REMOTE_AUGMENT, "datastore"),
-                    QName.create(SAL_REMOTE_AUGMENT, "notification-output-type")));
-        } catch (final ParseException e) {
-            final String errMsg = "It wasn't possible to convert revision date of sal-remote-augment to date";
-            LOG.debug(errMsg);
-            throw new RestconfDocumentedException(errMsg, ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED);
-        } catch (final URISyntaxException e) {
-            final String errMsg = "It wasn't possible to create instance of URI class with " + NETCONF_BASE + " URI";
-            throw new RestconfDocumentedException(errMsg, ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED);
-        }
-    }
+    private static final DateTimeFormatter FORMATTER = new DateTimeFormatterBuilder()
+            .appendValue(ChronoField.YEAR, 4).appendLiteral('-')
+            .appendValue(ChronoField.MONTH_OF_YEAR, 2).appendLiteral('-')
+            .appendValue(ChronoField.DAY_OF_MONTH, 2).appendLiteral('T')
+            .appendValue(ChronoField.HOUR_OF_DAY, 2).appendLiteral(':')
+            .appendValue(ChronoField.MINUTE_OF_HOUR, 2).appendLiteral(':')
+            .appendValue(ChronoField.SECOND_OF_MINUTE, 2)
+            .appendFraction(ChronoField.NANO_OF_SECOND, 0, 9, true)
+            .appendOffset("+HH:MM", "Z").toFormatter();
+
+    private BrokerFacade broker;
+
+    private ControllerContext controllerContext;
 
     public void setBroker(final BrokerFacade broker) {
         this.broker = broker;
@@ -417,8 +422,7 @@ public class RestconfImpl implements RestconfService {
         try {
             final String moduleName = pathArgs.get(0);
             final String revision = pathArgs.get(1);
-            final Date moduleRevision = SimpleDateFormatUtil.getRevisionFormat().parse(revision);
-            return QName.create(null, moduleRevision, moduleName);
+            return QName.create(null, SimpleDateFormatUtil.getRevisionFormat().parse(revision), moduleName);
         } catch (final ParseException e) {
             LOG.debug("URI has bad format. It should be \'moduleName/yyyy-MM-dd\' " + identifier);
             throw new RestconfDocumentedException("URI has bad format. It should be \'moduleName/yyyy-MM-dd\'",
@@ -1084,8 +1088,8 @@ public class RestconfImpl implements RestconfService {
         boolean startTime_used = false;
         boolean stopTime_used = false;
         boolean filter_used = false;
-        Date start = null;
-        Date stop = null;
+        Instant start = Instant.now();
+        Instant stop = null;
         String filter = null;
 
         for (final Entry<String, List<String>> entry : uriInfo.getQueryParameters().entrySet()) {
@@ -1148,30 +1152,16 @@ public class RestconfImpl implements RestconfService {
         throw new RestconfDocumentedException(msg);
     }
 
-    private static Date parseDateFromQueryParam(final Entry<String, List<String>> entry) {
+    private static Instant parseDateFromQueryParam(final Entry<String, List<String>> entry) {
         final DateAndTime event = new DateAndTime(entry.getValue().iterator().next());
-        String numOf_ms = "";
         final String value = event.getValue();
-        if (value.contains(".")) {
-            numOf_ms = numOf_ms + ".";
-            final int lastChar = value.contains("Z") ? value.indexOf("Z") : value.contains("+") ? value.indexOf("+")
-                    : value.contains("-") ? value.indexOf("-") : value.length();
-            for (int i = 0; i < lastChar - value.indexOf(".") - 1; i++) {
-                numOf_ms = numOf_ms + "S";
-            }
-        }
-        String zone = "";
-        if (!value.contains("Z")) {
-            zone = zone + "XXX";
-        }
-        final DateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss" + numOf_ms + zone);
-
+        final TemporalAccessor p;
         try {
-            return dateFormatter.parse(value.contains("Z") ? value.replace('T', ' ').substring(0, value.indexOf("Z"))
-                    : value.replace('T', ' '));
-        } catch (final ParseException e) {
-            throw new RestconfDocumentedException("Cannot parse of value in date: " + value + e);
+            p = FORMATTER.parse(value);
+        } catch (DateTimeParseException e) {
+            throw new RestconfDocumentedException("Cannot parse of value in date: " + value, e);
         }
+        return Instant.from(p);
     }
 
     /**
@@ -1204,11 +1194,11 @@ public class RestconfImpl implements RestconfService {
      * @param start
      *            - start-time of getting notification
      * @param filter
-     *            - indicate wh ich subset of allpossible events are of interest
+     *            - indicate which subset of all possible events are of interest
      * @return {@link URI} of location
      */
-    private URI notifStream(final String identifier, final UriInfo uriInfo, final Date start, final Date stop,
-            final String filter) {
+    private URI notifStream(final String identifier, final UriInfo uriInfo, final Instant start,
+            final Instant stop, final String filter) {
         final String streamName = Notificator.createStreamNameFromUri(identifier);
         if (Strings.isNullOrEmpty(streamName)) {
             throw new RestconfDocumentedException("Stream name is empty.", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
@@ -1221,7 +1211,7 @@ public class RestconfImpl implements RestconfService {
 
         for (final NotificationListenerAdapter listener : listeners) {
             this.broker.registerToListenNotification(listener);
-            listener.setQueryParams(start, stop, filter);
+            listener.setQueryParams(start, java.util.Optional.ofNullable(stop), java.util.Optional.ofNullable(filter));
         }
 
         final UriBuilder uriBuilder = uriInfo.getAbsolutePathBuilder();
@@ -1253,7 +1243,7 @@ public class RestconfImpl implements RestconfService {
      *            - indicate which subset of all possible events are of interest
      * @return {@link URI} of location
      */
-    private URI dataSubs(final String identifier, final UriInfo uriInfo, final Date start, final Date stop,
+    private URI dataSubs(final String identifier, final UriInfo uriInfo, final Instant start, final Instant stop,
             final String filter) {
         final String streamName = Notificator.createStreamNameFromUri(identifier);
         if (Strings.isNullOrEmpty(streamName)) {
@@ -1265,7 +1255,7 @@ public class RestconfImpl implements RestconfService {
             throw new RestconfDocumentedException("Stream was not found.", ErrorType.PROTOCOL,
                     ErrorTag.UNKNOWN_ELEMENT);
         }
-        listener.setQueryParams(start, stop, filter);
+        listener.setQueryParams(start, java.util.Optional.ofNullable(stop), java.util.Optional.ofNullable(filter));
 
         final Map<String, String> paramToValues = resolveValuesFromUri(identifier);
         final LogicalDatastoreType datastore =
index df9705cf762aeaac1d4bf9cf04f6361ebbe77473..67abe769a0210c3e063579d55cc576c6495ca16e 100644 (file)
@@ -7,8 +7,11 @@
  */
 package org.opendaylight.netconf.sal.streams.listeners;
 
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
 import java.io.StringReader;
-import java.util.Date;
+import java.time.Instant;
+import java.util.Optional;
 import javax.xml.XMLConstants;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
@@ -45,10 +48,15 @@ abstract class AbstractQueryParams extends AbstractNotificationsData {
     }
 
     // FIXME: these should be final
-    private Date start = null;
-    private Date stop = null;
+    private Instant start = null;
+    private Instant stop = null;
     private String filter = null;
 
+    @VisibleForTesting
+    public final Instant getStart() {
+        return start;
+    }
+
     /**
      * Set query parameters for listener
      *
@@ -59,10 +67,10 @@ abstract class AbstractQueryParams extends AbstractNotificationsData {
      * @param filter
      *            - indicate which subset of all possible events are of interest
      */
-    public void setQueryParams(final Date start, final Date stop, final String filter) {
-        this.start = start;
-        this.stop = stop;
-        this.filter = filter;
+    public void setQueryParams(final Instant start, final Optional<Instant> stop, final Optional<String> filter) {
+        this.start = Preconditions.checkNotNull(start);
+        this.stop = stop.orElse(null);
+        this.filter = filter.orElse(null);
     }
 
     /**
@@ -76,7 +84,7 @@ abstract class AbstractQueryParams extends AbstractNotificationsData {
      *         false otherwise
      */
     protected <T extends BaseListenerInterface> boolean checkQueryParams(final String xml, final T listener) {
-        final Date now = new Date();
+        final Instant now = Instant.now();
         if (this.stop != null) {
             if ((this.start.compareTo(now) < 0) && (this.stop.compareTo(now) > 0)) {
                 return checkFilter(xml);
index 4a25fcb35eef45ba8a5684300222255d80da46a1..efbb83a30d34071707066d7b7bc0caedb593d30d 100644 (file)
@@ -14,11 +14,11 @@ import static org.opendaylight.restconf.restful.utils.RestconfStreamsConstants.S
 
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
-import java.text.SimpleDateFormat;
-import java.util.Date;
+import java.time.Clock;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
 import java.util.List;
 import java.util.Map.Entry;
-import java.util.TimeZone;
 import javax.annotation.Nonnull;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
@@ -58,7 +58,8 @@ import org.slf4j.LoggerFactory;
  */
 public class RestconfDataServiceImpl implements RestconfDataService {
 
-    private final static Logger LOG = LoggerFactory.getLogger(RestconfDataServiceImpl.class);
+    private static final Logger LOG = LoggerFactory.getLogger(RestconfDataServiceImpl.class);
+    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MMM-dd HH:mm:ss");
 
     private final SchemaContextHandler schemaContextHandler;
     private final TransactionChainHandler transactionChainHandler;
@@ -104,11 +105,11 @@ public class RestconfDataServiceImpl implements RestconfDataService {
         }
         boolean tagged = false;
         if (withDefa_used) {
-            if (withDefa.equals("report-all-tagged")) {
+            if ("report-all-tagged".equals(withDefa)) {
                 tagged = true;
                 withDefa = null;
             }
-            if (withDefa.equals("report-all")) {
+            if ("report-all".equals(withDefa)) {
                 withDefa = null;
             }
         }
@@ -143,26 +144,18 @@ public class RestconfDataServiceImpl implements RestconfDataService {
                     RestconfError.ErrorType.PROTOCOL,
                     RestconfError.ErrorTag.DATA_MISSING);
         }
-        final SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");
-        dateFormatGmt.setTimeZone(TimeZone.getTimeZone("GMT"));
-        final String etag = '"' + node.getNodeType().getModule().getFormattedRevision()
-                + node.getNodeType().getLocalName() + '"';
-        final Response resp;
 
         if ((parameters.getContent().equals(RestconfDataServiceConstant.ReadData.ALL))
                     || parameters.getContent().equals(RestconfDataServiceConstant.ReadData.CONFIG)) {
-            resp = Response.status(200)
-                    .entity(new NormalizedNodeContext(instanceIdentifier, node, parameters))
-                    .header("ETag", etag)
-                    .header("Last-Modified", dateFormatGmt.format(new Date()))
-                    .build();
-        } else {
-            resp = Response.status(200)
+            return Response.status(200)
                     .entity(new NormalizedNodeContext(instanceIdentifier, node, parameters))
+                    .header("ETag", '"' + node.getNodeType().getModule().getFormattedRevision()
+                        + node.getNodeType().getLocalName() + '"')
+                    .header("Last-Modified", FORMATTER.format(LocalDateTime.now(Clock.systemUTC())))
                     .build();
         }
 
-        return resp;
+        return Response.status(200).entity(new NormalizedNodeContext(instanceIdentifier, node, parameters)).build();
     }
 
     @Override
@@ -341,11 +334,10 @@ public class RestconfDataServiceImpl implements RestconfDataService {
         final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
         if (domDataBrokerService.isPresent()) {
             return domDataBrokerService.get().createTransactionChain(RestConnectorProvider.transactionListener);
-        } else {
-            final String errMsg = "DOM data broker service isn't available for mount point "
-                    + mountPoint.getIdentifier();
-            LOG.warn(errMsg);
-            throw new RestconfDocumentedException(errMsg);
         }
+
+        final String errMsg = "DOM data broker service isn't available for mount point " + mountPoint.getIdentifier();
+        LOG.warn(errMsg);
+        throw new RestconfDocumentedException(errMsg);
     }
 }
index fb2c76ee49ef435d2f24e20704f8df2f99cdadee..e19a1754636e568ce576089bb9e1cca586526b83 100644 (file)
@@ -8,11 +8,13 @@
 package org.opendaylight.restconf.restful.services.impl;
 
 import java.net.URI;
-import java.util.Date;
+import java.time.Instant;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Optional;
+import javax.annotation.Nonnull;
 import javax.ws.rs.core.UriInfo;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
 import org.opendaylight.controller.md.sal.dom.api.DOMNotificationService;
@@ -67,8 +69,7 @@ public class RestconfStreamsSubscriptionServiceImpl implements RestconfStreamsSu
 
     @Override
     public NormalizedNodeContext subscribeToStream(final String identifier, final UriInfo uriInfo) {
-        final NotificationQueryParams notificationQueryParams = new NotificationQueryParams();
-        notificationQueryParams.prepareParams(uriInfo);
+        final NotificationQueryParams notificationQueryParams = NotificationQueryParams.fromUriInfo(uriInfo);
 
         URI response = null;
         if (identifier.contains(RestconfStreamsConstants.DATA_SUBSCR)) {
@@ -160,19 +161,24 @@ public class RestconfStreamsSubscriptionServiceImpl implements RestconfStreamsSu
      * Parser and holder of query paramteres from uriInfo for notifications
      *
      */
-    public final class NotificationQueryParams {
+    public static final class NotificationQueryParams {
 
-        private Date start = null;
-        private Date stop = null;
-        private String filter = null;
-
-        private NotificationQueryParams() {
+        private final Instant start;
+        private final Instant stop;
+        private final String filter;
 
+        private NotificationQueryParams(final Instant start, final Instant stop, final String filter) {
+            this.start = start == null ? Instant.now() : start;
+            this.stop = stop;
+            this.filter = filter;
         }
 
-        private void prepareParams(final UriInfo uriInfo) {
+        static NotificationQueryParams fromUriInfo(final UriInfo uriInfo) {
+            Instant start = null;
             boolean startTime_used = false;
+            Instant stop = null;
             boolean stopTime_used = false;
+            String filter = null;
             boolean filter_used = false;
 
             for (final Entry<String, List<String>> entry : uriInfo.getQueryParameters().entrySet()) {
@@ -180,7 +186,7 @@ public class RestconfStreamsSubscriptionServiceImpl implements RestconfStreamsSu
                     case "start-time":
                         if (!startTime_used) {
                             startTime_used = true;
-                            this.start = SubscribeToStreamUtil.parseDateFromQueryParam(entry);
+                            start = SubscribeToStreamUtil.parseDateFromQueryParam(entry);
                         } else {
                             throw new RestconfDocumentedException("Start-time parameter can be used only once.");
                         }
@@ -188,7 +194,7 @@ public class RestconfStreamsSubscriptionServiceImpl implements RestconfStreamsSu
                     case "stop-time":
                         if (!stopTime_used) {
                             stopTime_used = true;
-                            this.stop = SubscribeToStreamUtil.parseDateFromQueryParam(entry);
+                            stop = SubscribeToStreamUtil.parseDateFromQueryParam(entry);
                         } else {
                             throw new RestconfDocumentedException("Stop-time parameter can be used only once.");
                         }
@@ -196,7 +202,7 @@ public class RestconfStreamsSubscriptionServiceImpl implements RestconfStreamsSu
                     case "filter":
                         if (!filter_used) {
                             filter_used = true;
-                            this.filter = entry.getValue().iterator().next();
+                            filter = entry.getValue().iterator().next();
                         }
                         break;
                     default:
@@ -208,9 +214,7 @@ public class RestconfStreamsSubscriptionServiceImpl implements RestconfStreamsSu
                 throw new RestconfDocumentedException("Stop-time parameter has to be used with start-time parameter.");
             }
 
-            if (this.start == null) {
-                this.start = new Date();
-            }
+            return new NotificationQueryParams(start, stop, filter);
         }
 
         /**
@@ -218,8 +222,8 @@ public class RestconfStreamsSubscriptionServiceImpl implements RestconfStreamsSu
          *
          * @return start-time
          */
-        public Date getStart() {
-            return this.start;
+        public @Nonnull Instant getStart() {
+            return start;
         }
 
         /**
@@ -227,8 +231,8 @@ public class RestconfStreamsSubscriptionServiceImpl implements RestconfStreamsSu
          *
          * @return stop-time
          */
-        public Date getStop() {
-            return this.stop;
+        public Optional<Instant> getStop() {
+            return Optional.ofNullable(stop);
         }
 
         /**
@@ -236,8 +240,8 @@ public class RestconfStreamsSubscriptionServiceImpl implements RestconfStreamsSu
          *
          * @return filter
          */
-        public String getFilter() {
-            return this.filter;
+        public Optional<String> getFilter() {
+            return Optional.ofNullable(filter);
         }
     }
 
index 82bc4a02927890be0b0fdec9b0bdbf5a6d19a23f..6a6f29ceedf011cf6d7d7da586ae8c4e3d2c41b7 100644 (file)
@@ -7,7 +7,7 @@
  */
 package org.opendaylight.restconf.restful.utils;
 
-import com.google.common.collect.Sets;
+import com.google.common.collect.ImmutableSet;
 import java.net.URI;
 import java.text.ParseException;
 import java.util.Date;
@@ -21,7 +21,7 @@ import org.opendaylight.restconf.utils.parser.builder.ParserBuilderConstants;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -41,7 +41,22 @@ public final class RestconfStreamsConstants {
 
     public static final QNameModule SAL_REMOTE_AUGMENT;
 
-    public static final YangInstanceIdentifier.AugmentationIdentifier SAL_REMOTE_AUG_IDENTIFIER;
+    static {
+        final Date eventSubscriptionAugRevision;
+        try {
+            eventSubscriptionAugRevision = SimpleDateFormatUtil.getRevisionFormat().parse("2014-07-08");
+        } catch (final ParseException e) {
+            final String errMsg = "It wasn't possible to convert revision date of sal-remote-augment to date";
+            LOG.debug(errMsg);
+            throw new RestconfDocumentedException(errMsg, ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED);
+        }
+        SAL_REMOTE_AUGMENT = QNameModule.create(NAMESPACE_EVENT_SUBSCRIPTION_AUGMENT, eventSubscriptionAugRevision)
+                .intern();
+    }
+
+    public static final AugmentationIdentifier SAL_REMOTE_AUG_IDENTIFIER = new AugmentationIdentifier(
+        ImmutableSet.of(QName.create(SAL_REMOTE_AUGMENT, "scope"), QName.create(SAL_REMOTE_AUGMENT, "datastore"),
+            QName.create(SAL_REMOTE_AUGMENT, "notification-output-type")));
 
     public static final DataChangeScope DEFAULT_SCOPE = DataChangeScope.BASE;
 
@@ -71,21 +86,6 @@ public final class RestconfStreamsConstants {
     public static final String STREAM_ACCESS_PATH_PART = "/access=";
     public static final String STREAM_LOCATION_PATH_PART = "/location";
 
-    static {
-        Date eventSubscriptionAugRevision;
-        try {
-            eventSubscriptionAugRevision = SimpleDateFormatUtil.getRevisionFormat().parse("2014-07-08");
-        } catch (final ParseException e) {
-            final String errMsg = "It wasn't possible to convert revision date of sal-remote-augment to date";
-            LOG.debug(errMsg);
-            throw new RestconfDocumentedException(errMsg, ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED);
-        }
-        SAL_REMOTE_AUGMENT = QNameModule.create(NAMESPACE_EVENT_SUBSCRIPTION_AUGMENT, eventSubscriptionAugRevision);
-        SAL_REMOTE_AUG_IDENTIFIER = new YangInstanceIdentifier.AugmentationIdentifier(Sets
-                .newHashSet(QName.create(SAL_REMOTE_AUGMENT, "scope"), QName.create(SAL_REMOTE_AUGMENT, "datastore"),
-                        QName.create(SAL_REMOTE_AUGMENT, "notification-output-type")));
-    }
-
     private RestconfStreamsConstants() {
         throw new UnsupportedOperationException("Util class.");
     }
index 73ef1a91dee293fab86ad8887583c4720586b1de..8786f67639b164f038de68ea5344bbffb04dc29a 100644 (file)
@@ -10,11 +10,13 @@ package org.opendaylight.restconf.restful.utils;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Strings;
 import java.net.URI;
-import java.text.DateFormat;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
+import java.time.Instant;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
+import java.time.temporal.TemporalAccessor;
 import java.util.ArrayList;
-import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -69,6 +71,15 @@ import org.slf4j.LoggerFactory;
 public final class SubscribeToStreamUtil {
 
     private static final Logger LOG = LoggerFactory.getLogger(SubscribeToStreamUtil.class);
+    private static final DateTimeFormatter FORMATTER = new DateTimeFormatterBuilder()
+            .appendValue(ChronoField.YEAR, 4).appendLiteral('-')
+            .appendValue(ChronoField.MONTH_OF_YEAR, 2).appendLiteral('-')
+            .appendValue(ChronoField.DAY_OF_MONTH, 2).appendLiteral('T')
+            .appendValue(ChronoField.HOUR_OF_DAY, 2).appendLiteral(':')
+            .appendValue(ChronoField.MINUTE_OF_HOUR, 2).appendLiteral(':')
+            .appendValue(ChronoField.SECOND_OF_MINUTE, 2)
+            .appendFraction(ChronoField.NANO_OF_SECOND, 0, 9, true)
+            .appendOffset("+HH:MM", "Z").toFormatter();
 
     private SubscribeToStreamUtil() {
         throw new UnsupportedOperationException("Util class");
@@ -234,37 +245,24 @@ public final class SubscribeToStreamUtil {
 
     /**
      * Parse input of query parameters - start-time or stop-time - from
-     * {@link DateAndTime} format to {@link Date} format
+     * {@link DateAndTime} format to {@link Instant} format
      *
      * @param entry
      *            - start-time or stop-time as string in {@link DateAndTime}
      *            format
-     * @return parsed {@link Date} by entry
+     * @return parsed {@link Instant} by entry
      */
-    public static Date parseDateFromQueryParam(final Entry<String, List<String>> entry) {
+    public static Instant parseDateFromQueryParam(final Entry<String, List<String>> entry) {
         final DateAndTime event = new DateAndTime(entry.getValue().iterator().next());
-        String numOf_ms = "";
         final String value = event.getValue();
-        if (value.contains(".")) {
-            numOf_ms = numOf_ms + ".";
-            final int lastChar = value.contains("Z") ? value.indexOf("Z") : (value.contains("+") ? value.indexOf("+")
-                    : (value.contains("-") ? value.indexOf("-") : value.length()));
-            for (int i = 0; i < (lastChar - value.indexOf(".") - 1); i++) {
-                numOf_ms = numOf_ms + "S";
-            }
-        }
-        String zone = "";
-        if (!value.contains("Z")) {
-            zone = zone + "XXX";
-        }
-        final DateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss" + numOf_ms + zone);
-
+        final TemporalAccessor p;
         try {
-            return dateFormatter.parse(value.contains("Z") ? value.replace('T', ' ').substring(0, value.indexOf("Z"))
-                    : value.replace('T', ' '));
-        } catch (final ParseException e) {
-            throw new RestconfDocumentedException("Cannot parse of value in date: " + value + e);
+            p = FORMATTER.parse(value);
+        } catch (DateTimeParseException e) {
+            throw new RestconfDocumentedException("Cannot parse of value in date: " + value, e);
         }
+        return Instant.from(p);
+
     }
 
     @SuppressWarnings("rawtypes")
@@ -297,8 +295,7 @@ public final class SubscribeToStreamUtil {
      */
     public static Map<String, String> mapValuesFromUri(final String identifier) {
         final HashMap<String, String> result = new HashMap<>();
-        final String[] tokens = identifier.split(String.valueOf(RestconfConstants.SLASH));
-        for (final String token : tokens) {
+        for (final String token : RestconfConstants.SLASH_SPLITTER.split(identifier)) {
             final String[] paramToken = token.split(String.valueOf(RestconfStreamsConstants.EQUAL));
             if (paramToken.length == 2) {
                 result.put(paramToken[0], paramToken[1]);
index 07a83205e24625240a49d03e1925d72d77a7d748..d7539a61860a248fd3e23b9107635d65f4a3fd3a 100644 (file)
@@ -8,9 +8,11 @@
 package org.opendaylight.restconf.utils.mapping;
 
 import java.net.URI;
-import java.text.SimpleDateFormat;
+import java.time.Instant;
+import java.time.OffsetDateTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
 import java.util.Collection;
-import java.util.Date;
 import java.util.Set;
 import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
 import org.opendaylight.restconf.Rfc8040.IetfYangLibrary;
@@ -471,8 +473,8 @@ public final class RestconfMappingNodeUtil {
      */
     @SuppressWarnings("rawtypes")
     public static NormalizedNode mapYangNotificationStreamByIetfRestconfMonitoring(final QName notifiQName,
-            final Set<NotificationDefinition> notifications, final Date start, final String outputType, final URI uri,
-            final Module monitoringModule, final boolean existParent) {
+            final Set<NotificationDefinition> notifications, final Instant start, final String outputType,
+            final URI uri, final Module monitoringModule, final boolean existParent) {
         for (final NotificationDefinition notificationDefinition : notifications) {
             if (notificationDefinition.getQName().equals(notifiQName)) {
                 final DataSchemaNode streamListSchema = ((ContainerSchemaNode) ((ContainerSchemaNode) monitoringModule
@@ -497,7 +499,8 @@ public final class RestconfMappingNodeUtil {
                 if (start != null) {
                     prepareLeafAndFillEntryBuilder(streamEntry,
                         listSchema.getDataChildByName(MonitoringModule.LEAF_START_TIME_STREAM_QNAME),
-                        new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'XXX").format(start));
+                        DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(OffsetDateTime.ofInstant(start,
+                            ZoneId.systemDefault())));
                 }
                 prepareListAndFillEntryBuilder(streamEntry,
                         (ListSchemaNode) listSchema.getDataChildByName(MonitoringModule.LIST_ACCESS_STREAM_QNAME),
@@ -569,7 +572,7 @@ public final class RestconfMappingNodeUtil {
      */
     @SuppressWarnings("rawtypes")
     public static NormalizedNode mapDataChangeNotificationStreamByIetfRestconfMonitoring(
-            final YangInstanceIdentifier path, final Date start, final String outputType, final URI uri,
+            final YangInstanceIdentifier path, final Instant start, final String outputType, final URI uri,
             final Module monitoringModule, final boolean existParent, final SchemaContext schemaContext) {
         final SchemaNode schemaNode = ParserIdentifier
                 .toInstanceIdentifier(ParserIdentifier.stringFromYangInstanceIdentifier(path, schemaContext),
@@ -595,7 +598,7 @@ public final class RestconfMappingNodeUtil {
                 listSchema.getDataChildByName(MonitoringModule.LEAF_REPLAY_SUPP_STREAM_QNAME), true);
         prepareLeafAndFillEntryBuilder(streamEntry,
                 listSchema.getDataChildByName(MonitoringModule.LEAF_START_TIME_STREAM_QNAME),
-                new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'XXX").format(start));
+                DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(OffsetDateTime.ofInstant(start, ZoneId.systemDefault())));
         prepareListAndFillEntryBuilder(streamEntry,
                 (ListSchemaNode) listSchema.getDataChildByName(MonitoringModule.LIST_ACCESS_STREAM_QNAME), outputType,
                 uri);
index 2551e3ee3316db03e8bf15da7f58de139997d180..9fd7e0ac44010561e274a8ff1e04ab5354fce885 100644 (file)
@@ -12,7 +12,9 @@ import java.io.File;
 import java.io.FileReader;
 import java.io.IOException;
 import java.lang.reflect.Method;
+import java.time.Instant;
 import java.util.Collection;
+import java.util.Optional;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -133,7 +135,7 @@ public class ExpressionParserTest {
         final PathArgument pathValue = NodeIdentifier.create(QName.create("module", "2016-14-12", "localName"));
         Mockito.when(path.getLastPathArgument()).thenReturn(pathValue);
         final ListenerAdapter listener = Notificator.createListener(path, "streamName", NotificationOutputType.JSON);
-        listener.setQueryParams(null, null, filter);
+        listener.setQueryParams(Instant.now(), Optional.empty(), Optional.ofNullable(filter));
 
         // FIXME: do not use reflection here
         final Class<?> superclass = listener.getClass().getSuperclass().getSuperclass();
index fae6281d4a88d63152d96bd06c94d629b866ec6c..bed856403785ae325eade3a340b6e5fe99ea6048 100644 (file)
@@ -7,9 +7,8 @@
  */
 package org.opendaylight.controller.sal.restconf.impl.test;
 
-import java.lang.reflect.Field;
+import java.time.Instant;
 import java.util.ArrayList;
-import java.util.Date;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map.Entry;
@@ -235,16 +234,11 @@ public class RestconfImplNotificationSubscribingTest {
 
         final AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> change =
                 Mockito.mock(AsyncDataChangeEvent.class);
-        final Class<?> superclass = listener.getClass().getSuperclass().getSuperclass();
-        Field start = superclass.getDeclaredField("start");
-        start.setAccessible(true);
-        Date startOrig = (Date) start.get(listener);
+        Instant startOrig = listener.getStart();
         Assert.assertNotNull(startOrig);
         listener.onDataChanged(change);
 
-        start = superclass.getDeclaredField("start");
-        start.setAccessible(true);
-        startOrig = (Date) start.get(listener);
+        startOrig = listener.getStart();
         Assert.assertNull(startOrig);
     }
 
index a41f35270d6eacad3b535484059a4c7b95132434..16ef10055f461f5f4731643f204d59c9038b0c27 100644 (file)
@@ -32,20 +32,10 @@ abstract class AbstractBodyReaderTest {
 
     protected final static ControllerContext controllerContext = ControllerContext.getInstance();
     protected final MediaType mediaType;
-    private static Field uriField;
-    private static Field requestField;
     protected final static DOMMountPointServiceHandler mountPointServiceHandler = mock(
             DOMMountPointServiceHandler.class);
 
     AbstractBodyReaderTest() throws NoSuchFieldException, IllegalAccessException {
-        uriField = AbstractIdentifierAwareJaxRsProvider.class
-                .getDeclaredField("uriInfo");
-        uriField.setAccessible(true);
-
-        requestField = AbstractIdentifierAwareJaxRsProvider.class
-                .getDeclaredField("request");
-        requestField.setAccessible(true);
-
         mediaType = getMediaType();
 
         final Field mountPointServiceHandlerField = RestConnectorProvider.class.
@@ -75,7 +65,7 @@ abstract class AbstractBodyReaderTest {
         when(uriInfoMock.getPathParameters()).thenReturn(pathParm);
         when(uriInfoMock.getPathParameters(false)).thenReturn(pathParm);
         when(uriInfoMock.getPathParameters(true)).thenReturn(pathParm);
-        uriField.set(normalizedNodeProvider, uriInfoMock);
+        normalizedNodeProvider.setUriInfo(uriInfoMock);
 
         final Request request = mock(Request.class);
         if (isPost) {
@@ -84,7 +74,7 @@ abstract class AbstractBodyReaderTest {
             when(request.getMethod()).thenReturn("PUT");
         }
 
-        requestField.set(normalizedNodeProvider, request);
+        normalizedNodeProvider.setRequest(request);
     }
 
     protected static void checkNormalizedNodeContext(
index 599184bdcd047a7888fd2d17946d2d5530f2f17f..4a554a9da20adabd93c01cf2d5cb0cd52b5504cc 100644 (file)
@@ -12,10 +12,12 @@ import static org.junit.Assert.assertNotNull;
 import static org.mockito.Mockito.when;
 
 import java.net.URI;
-import java.text.SimpleDateFormat;
+import java.time.Instant;
+import java.time.OffsetDateTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -142,7 +144,7 @@ public class RestconfMappingNodeUtilTest {
     public void toStreamEntryNodeTest() throws Exception {
         final YangInstanceIdentifier path =
                 ParserIdentifier.toInstanceIdentifier("nested-module:depth1-cont/depth2-leaf1", schemaContextMonitoring, null).getInstanceIdentifier();
-        final Date start = new Date();
+        final Instant start = Instant.now();
         final String outputType = "XML";
         final URI uri = new URI("uri");
         final Module monitoringModule = schemaContextMonitoring
@@ -160,7 +162,7 @@ public class RestconfMappingNodeUtilTest {
 
     @Test
     public void toStreamEntryNodeNotifiTest() throws Exception {
-        final Date start = new Date();
+        final Instant start = Instant.now();
         final String outputType = "JSON";
         final URI uri = new URI("uri");
         final Module monitoringModule = schemaContextMonitoring
@@ -172,20 +174,20 @@ public class RestconfMappingNodeUtilTest {
 
         final QName notifiQName = QName.create("urn:nested:module", "2014-06-3", "notifi");
         final NormalizedNode mappedData =
-                RestconfMappingNodeUtil.mapYangNotificationStreamByIetfRestconfMonitoring(notifiQName, schemaContextMonitoring.getNotifications(), start,
-                        outputType, uri, monitoringModule, exist);
+                RestconfMappingNodeUtil.mapYangNotificationStreamByIetfRestconfMonitoring(notifiQName,
+                    schemaContextMonitoring.getNotifications(), start, outputType, uri, monitoringModule, exist);
         assertNotNull(mappedData);
         testData(map, mappedData);
     }
 
-    private static Map<QName, Object> prepareMap(final String name, final URI uri, final Date start,
+    private static Map<QName, Object> prepareMap(final String name, final URI uri, final Instant start,
             final String outputType) {
         final Map<QName, Object> map = new HashMap<>();
         map.put(MonitoringModule.LEAF_NAME_STREAM_QNAME, name);
         map.put(MonitoringModule.LEAF_LOCATION_ACCESS_QNAME, uri.toString());
         map.put(MonitoringModule.LEAF_REPLAY_SUPP_STREAM_QNAME, true);
-        map.put(MonitoringModule.LEAF_START_TIME_STREAM_QNAME,
-                new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'XXX").format(start));
+        map.put(MonitoringModule.LEAF_START_TIME_STREAM_QNAME, DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(
+            OffsetDateTime.ofInstant(start, ZoneId.systemDefault())));
         map.put(MonitoringModule.LEAF_ENCODING_ACCESS_QNAME, outputType);
         return map;
     }