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