8d9c67edbbf0ab820fbad7b85e0079d62756d115
[neutron.git] / northbound-api / src / main / java / org / opendaylight / neutron / northbound / api / AbstractNeutronNorthbound.java
1 /*
2  * Copyright (c) 2015 Intel Corporation and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.neutron.northbound.api;
10
11 import java.lang.reflect.Constructor;
12 import java.lang.reflect.InvocationTargetException;
13 import java.lang.reflect.ParameterizedType;
14 import java.net.HttpURLConnection;
15 import java.util.List;
16 import java.util.Objects;
17 import javax.ws.rs.core.Response;
18 import org.opendaylight.neutron.spi.INeutronCRUD;
19 import org.opendaylight.neutron.spi.INeutronObject;
20
21 public abstract class AbstractNeutronNorthbound<T extends INeutronObject<T>, R extends INeutronRequest<T>,
22         I extends INeutronCRUD<T>> {
23
24     // T extends INeutronObject<T> as 0th type argument
25     private static final int NEUTRON_ARGUMENT_TYPE_INDEX = 0;
26     // NeutronRequest extends INeutronRequest<T> as 1st type argument
27     private static final int NEUTRON_REQUEST_TYPE_INDEX = 1;
28
29     protected static final int HTTP_OK_BOTTOM = 200;
30     protected static final int HTTP_OK_TOP = 299;
31
32     private static final String INTERFACE_NAME_BASE = " CRUD Interface";
33     private static final String UUID_NO_EXIST_BASE = " UUID does not exist.";
34
35     private final I neutronCRUD;
36
37     protected AbstractNeutronNorthbound(I neutronCRUD) {
38         this.neutronCRUD = Objects.requireNonNull(neutronCRUD, "neutronCRUD");
39     }
40
41     protected final String serviceUnavailable() {
42         return getResourceName() + INTERFACE_NAME_BASE + RestMessages.SERVICEUNAVAILABLE.toString();
43     }
44
45     protected final String uuidNoExist() {
46         return getResourceName() + UUID_NO_EXIST_BASE;
47     }
48
49     protected abstract String getResourceName();
50
51     private <K> Class<K> getActualTypeArgument(final int typeIndex) {
52         ParameterizedType parameterizedType = (ParameterizedType) getClass().getGenericSuperclass();
53         @SuppressWarnings("unchecked")
54         Class<K> cls = (Class<K>) parameterizedType.getActualTypeArguments()[typeIndex];
55         return cls;
56     }
57
58     private R newNeutronRequest(T neutronObject) {
59         // return new R(neutronObject)
60
61         // argumentClass = T.class
62         Class<T> argumentClass = getActualTypeArgument(NEUTRON_ARGUMENT_TYPE_INDEX);
63         // cls = NeturonRequest.class
64         Class<R> cls = getActualTypeArgument(NEUTRON_REQUEST_TYPE_INDEX);
65         try {
66             // ctor = R constructor
67             Constructor<R> ctor = cls.getDeclaredConstructor(argumentClass);
68             return ctor.newInstance(neutronObject);
69         } catch (NoSuchMethodException | InstantiationException
70                  | IllegalAccessException | InvocationTargetException e) {
71             // This case shouldn't happen
72             throw new IllegalArgumentException(e);
73         }
74     }
75
76     protected I getNeutronCRUD() {
77         return this.neutronCRUD;
78     }
79
80     protected Response show(String uuid,
81             // return fields
82             List<String> fields) {
83         T ans = neutronCRUD.get(uuid);
84         if (ans == null) {
85             throw new ResourceNotFoundException(uuidNoExist());
86         }
87
88         if (fields.size() > 0) {
89             return Response.status(HttpURLConnection.HTTP_OK).entity(newNeutronRequest(ans.extractFields(fields)))
90                     .build();
91         } else {
92             return Response.status(HttpURLConnection.HTTP_OK).entity(newNeutronRequest(ans)).build();
93         }
94     }
95
96     protected Response create(final R input) {
97         if (input.isSingleton()) {
98             T singleton = input.getSingleton();
99
100             singleton.initDefaults();
101             neutronCRUD.add(singleton);
102         } else {
103             if (input.getBulk() == null) {
104                 throw new BadRequestException("Invalid requests");
105             }
106             for (T test : input.getBulk()) {
107                 test.initDefaults();
108                 neutronCRUD.add(test);
109             }
110         }
111         return Response.status(HttpURLConnection.HTTP_CREATED).entity(input).build();
112     }
113
114     protected void updateDelta(String uuid, T delta, T original) {
115     }
116
117     private boolean checkRevisionNumber(T original, T delta) {
118         // If new update is null ignore the original revision number
119         if (delta.getRevisionNumber() == null) {
120             return false;
121         }
122         // If what is stored is null no need for comparison
123         if (original.getRevisionNumber() == null) {
124             return false;
125         }
126         if (original.getRevisionNumber() > delta.getRevisionNumber()) {
127             return true;
128         }
129         return false;
130     }
131
132     protected Response update(String uuid, final R input) {
133         if (!input.isSingleton()) {
134             throw new BadRequestException("Only singleton edit supported");
135         }
136         T delta = input.getSingleton();
137         T original = neutronCRUD.get(uuid);
138         if (original == null) {
139             throw new ResourceNotFoundException(uuidNoExist());
140         }
141         if (checkRevisionNumber(original, delta)) {
142             return Response.status(HttpURLConnection.HTTP_OK).build();
143         }
144         updateDelta(uuid, delta, original);
145         /*
146          * update the object and return it
147          */
148         if (!neutronCRUD.update(uuid, delta)) {
149             throw new ResourceNotFoundException(uuidNoExist());
150         }
151         T updated = neutronCRUD.get(uuid);
152         return Response.status(HttpURLConnection.HTTP_OK).entity(newNeutronRequest(updated)).build();
153     }
154
155     protected Response delete(String uuid) {
156         /*
157          * remove it and return 204 status
158          */
159         if (!neutronCRUD.remove(uuid)) {
160             throw new ResourceNotFoundException(uuidNoExist());
161         }
162
163         return Response.status(HttpURLConnection.HTTP_NO_CONTENT).build();
164     }
165 }