1 /*
2 * Copyright (C) 2017-2019 Centre National d'Etudes Spatiales (CNES).
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 3.0 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1301 USA
18 */
19 package fr.cnes.doi.client;
20
21 import com.fasterxml.jackson.databind.ObjectMapper;
22 import fr.cnes.doi.exception.ClientCrossCiteException;
23 import fr.cnes.doi.utils.spec.Requirement;
24 import java.io.IOException;
25 import java.util.List;
26 import java.util.logging.Level;
27 import org.restlet.data.Reference;
28 import org.restlet.data.Status;
29 import org.restlet.representation.Representation;
30 import org.restlet.resource.ResourceException;
31
32 /**
33 * Client to query the citation service. This class queries
34 * <a href="https://citation.crosscite.org/">CrossCite</a>.
35 *
36 * @author Jean-Christophe Malapert (Jean-Christophe.malapert@cnes.fr)
37 */
38 @Requirement(reqId = Requirement.DOI_INTER_020, reqName = Requirement.DOI_INTER_020_NAME)
39 public class ClientCrossCiteCitation extends BaseClient {
40
41 /**
42 * Service end point {@value #CROSS_CITE_URL}.
43 */
44 public static final String CROSS_CITE_URL = "http://citation.crosscite.org";
45
46 /**
47 * Service end point {@value #CROSS_CITE_MOCK_URL}.
48 */
49 public static final String CROSS_CITE_MOCK_URL = "http://localhost:" + DATACITE_MOCKSERVER_PORT;
50
51 /**
52 * URI to get styles {@value #STYLE_URI}.
53 */
54 public static final String STYLE_URI = "styles";
55
56 /**
57 * URI to get locales {@value #LOCALE_URI}.
58 */
59 public static final String LOCALE_URI = "locales";
60
61 /**
62 * URI to get format {@value #FORMAT_URI}.
63 */
64 public static final String FORMAT_URI = "format";
65
66 /**
67 * Context use.
68 */
69 private final Context contextUse;
70
71 /**
72 * Creates a client to {@value CROSS_CITE_URL} with a
73 * {@link Context#PROD prod} context and without a proxy.
74 */
75 public ClientCrossCiteCitation() {
76 super(CROSS_CITE_URL);
77 this.contextUse = Context.PROD;
78 }
79
80 /**
81 * Creates a client to an URI related to the context.
82 *
83 * @param context context
84 */
85 public ClientCrossCiteCitation(final Context context) {
86 super(context.getCrossCiteUrl());
87 this.contextUse = context;
88 }
89
90 /**
91 * Init the endpoint.
92 */
93 protected void init() {
94 this.getClient().setReference(new Reference(this.contextUse.getCrossCiteUrl()));
95 }
96
97 /**
98 * Returns the response as a list of String of an URI.
99 *
100 * @param segment resource name
101 * @return the response
102 * @throws ClientCrossCiteException - if an error happens when requesting
103 * CrossCite
104 */
105 private List<String> getList(final String segment) throws ClientCrossCiteException {
106 try {
107 final Reference ref = getClient().addSegment(segment);
108 this.getClient().setReference(ref);
109 final Representation rep = this.getClient().get();
110 final Status status = this.getClient().getStatus();
111 if (status.isSuccess()) {
112 final ObjectMapper mapper = new ObjectMapper();
113 return mapper.readValue(rep.getStream(), List.class);
114 } else {
115 throw new ClientCrossCiteException(status, status.getDescription());
116 }
117 } catch (IOException | ResourceException ex) {
118 throw new ClientCrossCiteException(Status.SERVER_ERROR_INTERNAL, ex.getMessage(), ex);
119 } finally {
120 this.getClient().release();
121 }
122 }
123
124 /**
125 * Returns styles by calling {@value #STYLE_URI}.
126 *
127 * @return list of possible styles
128 * @throws fr.cnes.doi.exception.ClientCrossCiteException Will thrown an
129 * Exception when a problem happens during the request to Cross Cite
130 */
131 public List<String> getStyles() throws ClientCrossCiteException {
132 init();
133 return getList(STYLE_URI);
134 }
135
136 /**
137 * Returns languages by calling {@value #LOCALE_URI}.
138 *
139 * @return List of possible languages
140 * @throws fr.cnes.doi.exception.ClientCrossCiteException Will thrown an
141 * Exception when a problem happens during the request to Cross Cite
142 */
143 public List<String> getLanguages() throws ClientCrossCiteException {
144 init();
145 return getList(LOCALE_URI);
146 }
147
148 /**
149 * Returns the citation of a DOI based on the selected style and language.
150 *
151 * @param doiName DOI name
152 * @param style Selected style to format the citation
153 * @param language Selected language to format the citation
154 * @return The formatted citation
155 * @throws fr.cnes.doi.exception.ClientCrossCiteException Will thrown an
156 * Exception when a problem happens during the request to Cross Cite
157 */
158 public String getFormat(final String doiName,
159 final String style,
160 final String language) throws ClientCrossCiteException {
161 init();
162 final String result;
163 try {
164 Reference ref = this.getClient().addSegment(FORMAT_URI);
165 ref = ref.addQueryParameter("doi", doiName);
166 ref = ref.addQueryParameter("style", style);
167 ref = ref.addQueryParameter("lang", language);
168 this.getClient().setReference(ref);
169 final Representation rep = this.getClient().get();
170 final Status status = this.getClient().getStatus();
171 if (status.isSuccess()) {
172 result = rep.getText();
173 } else {
174 throw new ClientCrossCiteException(status, status.getDescription());
175 }
176 return result;
177 } catch (IOException ex) {
178 throw new ClientCrossCiteException(Status.SERVER_ERROR_INTERNAL, ex.getMessage(), ex);
179 } catch (ResourceException ex) {
180 throw new ClientCrossCiteException(ex.getStatus(), ex.getMessage(), ex);
181 } finally {
182 this.getClient().release();
183 }
184 }
185
186 /**
187 * Options for each context.
188 */
189 public enum Context {
190
191 /**
192 * Development context. This context uses the
193 * {@link #CROSS_CITE_MOCK_URL} end point with a log level sets to OFF.
194 */
195 DEV(CROSS_CITE_MOCK_URL, Level.OFF),
196 /**
197 * Post development context. This context uses the
198 * {@link #CROSS_CITE_URL} end point with a log level sets to ALL.
199 */
200 POST_DEV(CROSS_CITE_URL, Level.ALL),
201 /**
202 * Pre production context. This context uses the {@link #CROSS_CITE_URL}
203 * end point with a log level sets to FINE.
204 */
205 PRE_PROD(CROSS_CITE_URL, Level.FINE),
206 /**
207 * Production context. This context uses the {@link #CROSS_CITE_URL} end
208 * point with a log level sets to INFO.
209 */
210 PROD(CROSS_CITE_URL, Level.INFO);
211
212 /**
213 * Level log.
214 */
215 private Level levelLog;
216
217 /**
218 * CrossCite URL.
219 */
220 private String crossCiteUrl;
221
222 /**
223 * Construct a development context
224 *
225 * @param dataciteUrl dataciteURL according to the context
226 * @param levelLog level log
227 */
228 Context(final String dataciteUrl,
229 final Level levelLog) {
230 this.crossCiteUrl = dataciteUrl;
231 this.levelLog = levelLog;
232 }
233
234 /**
235 * Returns the log level.
236 *
237 * @return the log level
238 */
239 public Level getLevelLog() {
240 return this.levelLog;
241 }
242
243 /**
244 * Returns the service end point.
245 *
246 * @return the service end point
247 */
248 public String getCrossCiteUrl() {
249 return this.crossCiteUrl;
250 }
251
252 /**
253 * Sets the level log for the context
254 *
255 * @param levelLog level log
256 */
257 private void setLevelLog(final Level levelLog) {
258 this.levelLog = levelLog;
259 }
260
261 /**
262 * Sets the Cross Cite URL for the context.
263 *
264 * @param crossCiteUrl Cross Cite URL
265 */
266 private void setCrossCiteUrl(final String crossCiteUrl) {
267 this.crossCiteUrl = crossCiteUrl;
268 }
269
270 /**
271 * Sets the level log for a given context
272 *
273 * @param context the context
274 * @param levelLog the level log
275 */
276 public static void setLevelLog(final Context context,
277 final Level levelLog) {
278 context.setLevelLog(levelLog);
279 }
280
281 /**
282 * Sets the Cross Cite URL for a given context
283 *
284 * @param context the context
285 * @param crossCiteUrl Cross Cite URL
286 */
287 public static void setCrossCiteUrl(final Context context,
288 final String crossCiteUrl) {
289 context.setCrossCiteUrl(crossCiteUrl);
290 }
291
292 }
293 }