View Javadoc
1   /*
2    * This file is part of Waarp Project (named also Waarp or GG).
3    *
4    *  Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
5    *  tags. See the COPYRIGHT.txt in the distribution for a full listing of
6    * individual contributors.
7    *
8    *  All Waarp Project is free software: you can redistribute it and/or
9    * modify it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation, either version 3 of the License, or (at your
11   * option) any later version.
12   *
13   * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
14   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15   * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16   *
17   *  You should have received a copy of the GNU General Public License along with
18   * Waarp . If not, see <http://www.gnu.org/licenses/>.
19   */
20  
21  package org.waarp.openr66.protocol.http.restv2.dbhandlers;
22  
23  import com.fasterxml.jackson.databind.node.ArrayNode;
24  import com.fasterxml.jackson.databind.node.ObjectNode;
25  import io.cdap.http.HttpResponder;
26  import io.netty.handler.codec.http.DefaultHttpHeaders;
27  import io.netty.handler.codec.http.HttpHeaders;
28  import io.netty.handler.codec.http.HttpMethod;
29  import io.netty.handler.codec.http.HttpRequest;
30  import org.waarp.common.json.JsonHandler;
31  import org.waarp.common.role.RoleDefault.ROLE;
32  import org.waarp.common.utility.ParametersChecker;
33  import org.waarp.openr66.dao.DAOFactory;
34  import org.waarp.openr66.dao.Filter;
35  import org.waarp.openr66.dao.RuleDAO;
36  import org.waarp.openr66.dao.exception.DAOConnectionException;
37  import org.waarp.openr66.pojo.Rule;
38  import org.waarp.openr66.protocol.http.restv2.errors.RestError;
39  import org.waarp.openr66.protocol.http.restv2.errors.RestErrorException;
40  import org.waarp.openr66.protocol.http.restv2.utils.RestUtils;
41  
42  import javax.ws.rs.Consumes;
43  import javax.ws.rs.DefaultValue;
44  import javax.ws.rs.GET;
45  import javax.ws.rs.InternalServerErrorException;
46  import javax.ws.rs.OPTIONS;
47  import javax.ws.rs.POST;
48  import javax.ws.rs.Path;
49  import javax.ws.rs.QueryParam;
50  import java.util.ArrayList;
51  import java.util.Collections;
52  import java.util.List;
53  
54  import static io.netty.handler.codec.http.HttpResponseStatus.*;
55  import static javax.ws.rs.core.HttpHeaders.*;
56  import static javax.ws.rs.core.MediaType.*;
57  import static org.waarp.openr66.dao.database.DBRuleDAO.*;
58  import static org.waarp.openr66.protocol.http.restv2.RestConstants.*;
59  import static org.waarp.openr66.protocol.http.restv2.RestConstants.GetRulesParams.*;
60  import static org.waarp.openr66.protocol.http.restv2.converters.RuleConverter.*;
61  import static org.waarp.openr66.protocol.http.restv2.converters.RuleConverter.Order.*;
62  import static org.waarp.openr66.protocol.http.restv2.errors.RestErrors.*;
63  import static org.waarp.openr66.protocol.http.restv2.utils.JsonUtils.*;
64  
65  /**
66   * This is the {@link AbstractRestDbHandler} handling all operations on the
67   * host's transfer rule database.
68   */
69  @Path(RULES_HANDLER_URI)
70  public class RulesHandler extends AbstractRestDbHandler {
71  
72    /**
73     * The content of the 'Allow' header sent when an 'OPTIONS' request is made
74     * on the handler.
75     */
76    private static final HttpHeaders OPTIONS_HEADERS;
77  
78    static {
79      OPTIONS_HEADERS = new DefaultHttpHeaders();
80      final List<HttpMethod> allow = new ArrayList<HttpMethod>();
81      allow.add(HttpMethod.GET);
82      allow.add(HttpMethod.POST);
83      allow.add(HttpMethod.OPTIONS);
84      OPTIONS_HEADERS.add(ALLOW, allow);
85    }
86  
87    public RulesHandler(final byte crud) {
88      super(crud);
89    }
90  
91    /**
92     * Method called to obtain a list of transfer rules based on the filters in
93     * the query parameters.
94     *
95     * @param request the HttpRequest made on the resource
96     * @param responder the HttpResponder which sends the reply to the
97     *     request
98     * @param limitStr the maximum number of entries allowed in the
99     *     response
100    * @param offsetStr the index of the first accepted entry in the
101    *     list of all valid answers
102    * @param orderStr the criteria used to sort the entries and the
103    *     way of ordering them
104    * @param modeTransStr only keep rules that use this transfer mode
105    */
106   @GET
107   @Consumes(APPLICATION_FORM_URLENCODED)
108   @RequiredRole(ROLE.READONLY)
109   public final void filterRules(final HttpRequest request,
110                                 final HttpResponder responder,
111                                 @QueryParam(LIMIT) @DefaultValue("20")
112                                 final String limitStr,
113                                 @QueryParam(OFFSET) @DefaultValue("0")
114                                 final String offsetStr,
115                                 @QueryParam(ORDER) @DefaultValue("ascName")
116                                 final String orderStr,
117                                 @QueryParam(MODE_TRANS) @DefaultValue("")
118                                 final String modeTransStr,
119                                 @QueryParam(COUNT_ORDER) @DefaultValue("")
120                                 final String countOrder) {
121     checkSanity(limitStr, offsetStr, orderStr, modeTransStr, countOrder);
122     final List<RestError> errors = new ArrayList<RestError>();
123 
124     boolean count = false;
125     try {
126       if (ParametersChecker.isNotEmpty(countOrder) &&
127           RestUtils.stringToBoolean(countOrder)) {
128         count = true;
129       }
130     } catch (final Exception ignore) {
131       // Ignore
132     }
133     int limit = 20;
134     int offset = 0;
135     Order order = ascName;
136     ModeTrans modeTrans = null;
137     try {
138       limit = Integer.parseInt(limitStr);
139       order = Order.valueOf(orderStr);
140     } catch (final NumberFormatException e) {
141       errors.add(ILLEGAL_PARAMETER_VALUE(LIMIT, limitStr));
142     } catch (final IllegalArgumentException e) {
143       errors.add(ILLEGAL_PARAMETER_VALUE(ORDER, orderStr));
144     }
145     try {
146       offset = Integer.parseInt(offsetStr);
147       if (!modeTransStr.isEmpty()) {
148         modeTrans = ModeTrans.valueOf(modeTransStr);
149       }
150     } catch (final NumberFormatException e) {
151       errors.add(ILLEGAL_PARAMETER_VALUE(OFFSET, offsetStr));
152     } catch (final IllegalArgumentException e) {
153       errors.add(ILLEGAL_PARAMETER_VALUE(MODE_TRANS, e.getMessage()));
154     }
155 
156     if (limit <= 0) {
157       errors.add(ILLEGAL_PARAMETER_VALUE(LIMIT, limitStr));
158     } else if (offset < 0) {
159       errors.add(ILLEGAL_PARAMETER_VALUE(OFFSET, offsetStr));
160     }
161 
162     if (!errors.isEmpty()) {
163       throw new RestErrorException(errors);
164     }
165     final List<Filter> filters = new ArrayList<Filter>();
166     if (modeTrans != null) {
167       filters.add(new Filter(MODE_TRANS_FIELD, "=",
168                              Integer.toString(modeTrans.ordinal())));
169     }
170 
171     final ObjectNode responseObject = JsonHandler.createObjectNode();
172     RuleDAO ruleDAO = null;
173     if (count) {
174       long nbCount = -1;
175       try {
176         ruleDAO = DAO_FACTORY.getRuleDAO(false);
177         nbCount = ruleDAO.count(filters);
178       } catch (final DAOConnectionException e) {
179         throw new InternalServerErrorException(e);
180       } finally {
181         DAOFactory.closeDAO(ruleDAO);
182       }
183       responseObject.put("totalResults", nbCount);
184     } else {
185       List<Rule> rules;
186       try {
187         ruleDAO = DAO_FACTORY.getRuleDAO(false);
188         rules = ruleDAO.find(filters);
189       } catch (final DAOConnectionException e) {
190         throw new InternalServerErrorException(e);
191       } finally {
192         DAOFactory.closeDAO(ruleDAO);
193       }
194       final int totalResults = rules.size();
195       Collections.sort(rules, order.comparator);
196 
197       final ArrayNode results = JsonHandler.createArrayNode();
198       for (int i = offset; i < offset + limit && i < rules.size(); i++) {
199         results.add(ruleToNode(rules.get(i)));
200       }
201       responseObject.put("totalResults", totalResults);
202       responseObject.set("results", results);
203     }
204     final String responseText = nodeToString(responseObject);
205     responder.sendJson(OK, responseText);
206   }
207 
208   /**
209    * Method called to add a new transfer rule in the server database. The
210    * reply will contain the created entry
211    * in JSON format, unless an unexpected error prevents it or if the request
212    * is invalid.
213    *
214    * @param request the HttpRequest made on the resource
215    * @param responder the HttpResponder which sends the reply to the
216    *     request.
217    */
218   @POST
219   @Consumes(APPLICATION_JSON)
220   @RequiredRole(ROLE.RULE)
221   public final void addRule(final HttpRequest request,
222                             final HttpResponder responder) {
223     final ObjectNode requestObject = deserializeRequest(request);
224     checkSanity(requestObject);
225     final Rule rule = nodeToNewRule(requestObject);
226 
227     RuleDAO ruleDAO = null;
228     try {
229       ruleDAO = DAO_FACTORY.getRuleDAO(false);
230 
231       if (ruleDAO.exist(rule.getName())) {
232         throw new RestErrorException(ALREADY_EXISTING(rule.getName()));
233       }
234 
235       ruleDAO.insert(rule);
236     } catch (final DAOConnectionException e) {
237       throw new InternalServerErrorException(e);
238     } finally {
239       DAOFactory.closeDAO(ruleDAO);
240     }
241 
242     final ObjectNode responseObject = ruleToNode(rule);
243     final String responseText = nodeToString(responseObject);
244 
245     final DefaultHttpHeaders headers = new DefaultHttpHeaders();
246     headers.add(CONTENT_TYPE, APPLICATION_JSON);
247     headers.add("ruleURI", RULES_HANDLER_URI + rule.getName());
248 
249     responder.sendString(CREATED, responseText, headers);
250   }
251 
252   /**
253    * Method called to get a list of all allowed HTTP methods on this entry
254    * point. The HTTP methods are sent as
255    * an array in the reply's headers.
256    *
257    * @param request the HttpRequest made on the resource
258    * @param responder The {@link HttpResponder} which sends the reply
259    *     to the request.
260    */
261   @OPTIONS
262   @Consumes(WILDCARD)
263   @RequiredRole(ROLE.NOACCESS)
264   public final void options(final HttpRequest request,
265                             final HttpResponder responder) {
266     responder.sendStatus(OK, OPTIONS_HEADERS);
267   }
268 }