View Javadoc
1   package com.srv4pos.server.api.product;
2   
3   import com.srv4pos.commons.io.InputStreamConnectionWriter;
4   //CHECKSTYLE:OFF Unused import (this one for javadoc)
5   import com.srv4pos.server.api.infrastructure.Constraints;
6   //CHECKSTYLE:ON Unused import (this one for javadoc)
7   import com.srv4pos.server.api.infrastructure.EmptyConnectionWriter;
8   import com.srv4pos.server.api.infrastructure.HttpMethod;
9   import com.srv4pos.server.api.infrastructure.IdentifierInfo;
10  import com.srv4pos.server.api.infrastructure.StringConnectionWriter;
11  import com.srv4pos.server.api.infrastructure.credentials.Credentials;
12  import com.srv4pos.server.api.infrastructure.http.HttpHelper;
13  import com.srv4pos.server.api.infrastructure.http.Transport;
14  import com.srv4pos.server.api.infrastructure.picture.ProductPictureInfo;
15  import com.srv4pos.server.api.infrastructure.request.StreamResponse;
16  import com.srv4pos.server.api.infrastructure.request.StringResponse;
17  import flexjson.JSONDeserializer;
18  
19  import java.io.InputStream;
20  import java.net.URL;
21  import java.util.HashMap;
22  import java.util.List;
23  import java.util.Map;
24  
25  import static com.srv4pos.server.api.infrastructure.http.HttpHelper.CONTENT_TYPE_APPLICATION_JSON;
26  import static com.srv4pos.server.api.infrastructure.http.HttpHelper.CONTENT_TYPE_PNG;
27  import static com.srv4pos.server.api.infrastructure.http.HttpHelper.encodePictureFilename;
28  import static com.srv4pos.server.api.infrastructure.request.RequestHelper.requestStream;
29  import static com.srv4pos.server.api.infrastructure.request.RequestHelper.requestString;
30  import static com.srv4pos.server.api.infrastructure.request.RequestHelper.requestVoid;
31  import static java.lang.String.format;
32  
33  /**
34   * For reaching Product entity. <p>User: Kirill, Date: 05.08.13 18:00</p>.
35   */
36  public class ProductService {
37  
38      private URL url;
39      private Credentials credentials;
40      private Transport transport;
41  
42      /**
43       * Constructs the service.
44       *
45       * @param url         of the server
46       * @param credentials to work with the server
47       * @param transport   to know the method to reach the server
48       */
49      public ProductService(URL url, Credentials credentials, Transport transport) {
50          this.url = url;
51          this.credentials = credentials;
52          this.transport = transport;
53      }
54  
55      /**
56       * Returns an entity.
57       *
58       * @param version    latest version of seller, may be null (if latest data needed)
59       * @param identifier identifies entity. must match to {@link Constraints#WINDOWS_FILENAME_REGEX}
60       * @return null if not modified since version or entity. if version is null then return value can not be null
61       * @throws com.srv4pos.server.api.exceptions.VersionConflictJsonException if version mismatch
62       * @throws com.srv4pos.server.api.exceptions.NotFoundJsonException        if entity is not found
63       */
64      public ProductInfo get(Integer version, String identifier) {
65          StringResponse response = requestString(
66                  format("%s/products/%s", credentials.getSellerId(), identifier),
67                  HttpMethod.GET,
68                  url,
69                  credentials.toAuthentication(),
70                  HttpHelper.integerToETag(version),
71                  null,
72                  EmptyConnectionWriter.EMPTY_CONNECTION_WRITER,
73                  HttpHelper.CONTENT_TYPE_APPLICATION_JSON,
74                  transport
75          );
76          return response == null ? null : ProductInfo.fromJsonToProductInfo(response.getContent());
77      }
78  
79      /**
80       * Put product to the server.
81       *
82       * @param version     expected latest version of seller
83       * @param productInfo data to put
84       * @throws com.srv4pos.server.api.exceptions.VersionConflictJsonException   if version mismatch
85       * @throws com.srv4pos.server.api.exceptions.ReferenceNotFoundJsonException if tax in {@link com.srv4pos.server.api.product.ProductInfo#tax}  is not found
86       */
87      public void put(int version, ProductInfo productInfo) {
88          requestVoid(
89                  format("%s/products/%s", credentials.getSellerId(), productInfo.getIdentifier()),
90                  HttpMethod.PUT,
91                  url,
92                  credentials.toAuthentication(),
93                  HttpHelper.integerToETag(version),
94                  null,
95                  new StringConnectionWriter(productInfo.toJson()),
96                  HttpHelper.CONTENT_TYPE_APPLICATION_JSON,
97                  transport
98          );
99      }
100 
101     /**
102      * Create product on the server.
103      *
104      * @param version     expected latest version of seller
105      * @param productInfo data to put
106      * @return identifier info
107      * @throws com.srv4pos.server.api.exceptions.VersionConflictJsonException   if version mismatch
108      * @throws com.srv4pos.server.api.exceptions.ReferenceNotFoundJsonException if tax in {@link com.srv4pos.server.api.product.ProductInfo#tax}  is not found
109      */
110     public IdentifierInfo create(int version, ProductInfo productInfo) {
111         return IdentifierInfo.fromJsonToIdentifierInfo(
112                 requestString(
113                         format("%s/products", credentials.getSellerId()),
114                         HttpMethod.POST,
115                         url,
116                         credentials.toAuthentication(),
117                         HttpHelper.integerToETag(version),
118                         null,
119                         new StringConnectionWriter(productInfo.toJson()),
120                         HttpHelper.CONTENT_TYPE_APPLICATION_JSON,
121                         transport
122                 ).getContent()
123         );
124     }
125 
126     /**
127      * Delete entity from the server.
128      *
129      * @param version    current seller version
130      * @param identifier identifies entity. must match to {@link Constraints#WINDOWS_FILENAME_REGEX}
131      * @throws com.srv4pos.server.api.exceptions.VersionConflictJsonException if version mismatch
132      */
133     public void delete(int version, String identifier) {
134         requestVoid(
135                 format("%s/products/%s", credentials.getSellerId(), identifier),
136                 HttpMethod.DELETE,
137                 url,
138                 credentials.toAuthentication(),
139                 HttpHelper.integerToETag(version),
140                 null,
141                 EmptyConnectionWriter.EMPTY_CONNECTION_WRITER,
142                 HttpHelper.CONTENT_TYPE_APPLICATION_JSON,
143                 transport
144         );
145     }
146 
147     /**
148      * Returns list of item changes between two versions.
149      *
150      * @param versionFrom version from included
151      * @param versionTo   version to included
152      * @return list of items to be added, edited or deleted ({@link com.srv4pos.server.api.product.ProductInfo#deleted} = true)
153      */
154     public List<ProductInfo> listDiff(int versionFrom, int versionTo) {
155         StringResponse response = requestString(
156                 format("%s/products-diff/%s/%s", credentials.getSellerId(), versionFrom, versionTo),
157                 HttpMethod.GET,
158                 url,
159                 credentials.toAuthentication(),
160                 null,
161                 null,
162                 EmptyConnectionWriter.EMPTY_CONNECTION_WRITER,
163                 HttpHelper.CONTENT_TYPE_APPLICATION_JSON,
164                 transport
165         );
166         return (List<ProductInfo>) ProductInfo.fromJsonArrayToProductInfoes(response.getContent());
167     }
168 
169     /**
170      * Returns list of entities.
171      *
172      * @param version version or null if fresh data required
173      * @return list of entities which exists on current seller or null if list of entities is not modified since version
174      */
175     public List<ProductInfo> list(Integer version) {
176         return list(version, null, null, null, null, null);
177     }
178 
179     /**
180      * Returns list of entities.
181      *
182      * @param firstResult when pagination starts or null
183      * @param maxResults  amount of items per page or null
184      * @param like        search string filter or null
185      * @param orderBy     field to order by, possible values are "IDENTIFIER", "NAME", "BARCODE", "NETTO", "TAX_NAME", "SALES_UNIT", "COUNTED_IN_PRICE"
186      * @param orderDesc   field to direction of ordering
187      * @param version     version or null if fresh data required
188      * @return list of entities which exists on current seller or null if list of entities is not modified since version
189      */
190     public List<ProductInfo> list(Integer version,
191                                   Integer firstResult,
192                                   Integer maxResults,
193                                   String like,
194                                   ProductInfo.Fields orderBy,
195                                   Boolean orderDesc) {
196         HashMap<String, String> params = new HashMap<String, String>();
197         if (orderBy != null) {
198             params.put("orderBy", orderBy.name());
199         }
200         if (orderDesc != null) {
201             params.put("orderDesc", orderDesc.toString());
202         }
203         if (firstResult != null) {
204             params.put("firstResult", Integer.toString(firstResult));
205         }
206         if (maxResults != null) {
207             params.put("maxResults", Integer.toString(maxResults));
208         }
209         if (like != null) {
210             params.put("like", like);
211         }
212 
213         StringResponse response = requestString(
214                 format("%s/products", credentials.getSellerId()),
215                 HttpMethod.GET,
216                 url,
217                 credentials.toAuthentication(),
218                 HttpHelper.integerToETag(version),
219                 params,
220                 EmptyConnectionWriter.EMPTY_CONNECTION_WRITER,
221                 HttpHelper.CONTENT_TYPE_APPLICATION_JSON,
222                 transport
223         );
224         return response == null ? null : (List<ProductInfo>) ProductInfo.fromJsonArrayToProductInfoes(response.getContent());
225     }
226 
227     /**
228      * Returns list of advanced entities.
229      *
230      * @param firstResult when pagination starts or null
231      * @param maxResults  amount of items per page or null
232      * @param like        search string filter or null
233      * @param orderBy     field to order by, possible values are "IDENTIFIER", "NAME", "BARCODE", "NETTO", "TAX_NAME", "SALES_UNIT", "COUNTED_IN_PRICE"
234      * @param orderDesc   field to direction of ordering
235      * @param version     version or null if fresh data required
236      * @return list of entities which exists on current seller or null if list of entities is not modified since version
237      */
238     public List<ProductAdvancedInfo> listAdvanced(Integer version,
239                                   Integer firstResult,
240                                   Integer maxResults,
241                                   String like,
242                                   ProductInfo.Fields orderBy,
243                                   Boolean orderDesc) {
244         HashMap<String, String> params = new HashMap<String, String>();
245         if (orderBy != null) {
246             params.put("orderBy", orderBy.name());
247         }
248         if (orderDesc != null) {
249             params.put("orderDesc", orderDesc.toString());
250         }
251         if (firstResult != null) {
252             params.put("firstResult", Integer.toString(firstResult));
253         }
254         if (maxResults != null) {
255             params.put("maxResults", Integer.toString(maxResults));
256         }
257         if (like != null) {
258             params.put("like", like);
259         }
260 
261         StringResponse response = requestString(
262                 format("%s/products-advanced", credentials.getSellerId()),
263                 HttpMethod.GET,
264                 url,
265                 credentials.toAuthentication(),
266                 HttpHelper.integerToETag(version),
267                 params,
268                 EmptyConnectionWriter.EMPTY_CONNECTION_WRITER,
269                 HttpHelper.CONTENT_TYPE_APPLICATION_JSON,
270                 transport
271         );
272         return response == null ? null : (List<ProductAdvancedInfo>) ProductAdvancedInfo.fromJsonArrayToProductAdvancedInfoes(response.getContent());
273     }
274 
275     /**
276      * Returns list of product pictures changes between two versions.
277      *
278      * @param versionFrom version from included
279      * @param versionTo   version to included
280      * @return list of items to be added, edited or deleted
281      * @see ProductServiceSample
282      */
283     public List<ProductPictureInfo> listDiffPicture(int versionFrom, int versionTo) {
284         StringResponse response = requestString(
285                 format("%s/product-images-diff/%s/%s", credentials.getSellerId(), versionFrom, versionTo),
286                 HttpMethod.GET,
287                 url,
288                 credentials.toAuthentication(),
289                 null,
290                 null,
291                 EmptyConnectionWriter.EMPTY_CONNECTION_WRITER,
292                 HttpHelper.CONTENT_TYPE_APPLICATION_JSON,
293                 transport
294         );
295         return (List<ProductPictureInfo>) ProductPictureInfo.fromJsonArrayToProductPictureInfoes(response.getContent());
296     }
297 
298     /**
299      * Returns body of the picture.
300      *
301      * @param version           picture version or null if fresh content needed
302      * @param productIdentifier product identifier
303      * @param pictureFilename   just a normal windows filename according to {@link Constraints#WINDOWS_FILENAME_REGEX}
304      * @return body in bytes or null if not modified (if version parameter is not null and seller has the same version as specified)
305      * @throws com.srv4pos.server.api.exceptions.NotFoundJsonException          if image is not found
306      * @throws com.srv4pos.server.api.exceptions.ReferenceNotFoundJsonException if product is not found
307      * @see ProductServiceSample
308      */
309     public InputStream getPicture(Integer version, String productIdentifier, String pictureFilename) {
310         final StreamResponse img = requestStream(
311                 formatPictureUrl(productIdentifier, pictureFilename, null),
312                 HttpMethod.GET,
313                 url,
314                 credentials == null ? null : credentials.toAuthentication(),
315                 HttpHelper.integerToETag(version),
316                 null,
317                 EmptyConnectionWriter.EMPTY_CONNECTION_WRITER,
318                 CONTENT_TYPE_PNG,
319                 transport
320         );
321         return img == null ? null : img.getContent();
322     }
323 
324     /**
325      * Returns list of picture relative paths .
326      *
327      * @param version           picture version or null if fresh content needed
328      * @param productIdentifier product identifier
329      * @return list of paths or null if not modified (if version parameter is not null and seller has the same version as specified)
330      * @throws com.srv4pos.server.api.exceptions.ReferenceNotFoundJsonException if seller is not found
331      * @see ProductServiceSample
332      */
333     public List<String> getPicturePath(Integer version, String productIdentifier) {
334         final StringResponse response = requestString(
335                 format("%s/products/%s/images", credentials.getSellerId(), productIdentifier),
336                 HttpMethod.GET,
337                 url,
338                 credentials.toAuthentication(),
339                 HttpHelper.integerToETag(version),
340                 null,
341                 EmptyConnectionWriter.EMPTY_CONNECTION_WRITER,
342                 CONTENT_TYPE_APPLICATION_JSON,
343                 transport
344         );
345 
346         return new JSONDeserializer<List<String>>().use("values", String.class).deserialize(response.getContent());
347     }
348 
349     /**
350      * Returns body of the picture for particular version number.
351      *
352      * @param pictureVersion    particular version of picture
353      * @param productIdentifier product identifier
354      * @param pictureFilename   just a normal windows filename according to {@link Constraints#WINDOWS_FILENAME_REGEX}
355      * @return body of the picture
356      * @throws com.srv4pos.server.api.exceptions.NotFoundJsonException          if image is not found
357      * @throws com.srv4pos.server.api.exceptions.ReferenceNotFoundJsonException if product is not found
358      * @see ProductServiceSample
359      */
360     public InputStream getPictureFromHistory(Integer pictureVersion, String productIdentifier, String pictureFilename) {
361         final StreamResponse img = requestStream(
362                 formatPictureUrl(productIdentifier, pictureFilename, pictureVersion),
363                 HttpMethod.GET,
364                 url,
365                 credentials == null ? null : credentials.toAuthentication(),
366                 null,
367                 null,
368                 EmptyConnectionWriter.EMPTY_CONNECTION_WRITER,
369                 HttpHelper.CONTENT_TYPE_PNG,
370                 transport
371         );
372         return img == null ? null : img.getContent();
373     }
374 
375     /**
376      * Send picture to the server.
377      *
378      * @param version           expected latest version of seller
379      * @param productIdentifier identifier of the product. must match to {@link Constraints#WINDOWS_FILENAME_REGEX}
380      * @param pictureFilename   picture filename. must match to {@link Constraints#WINDOWS_FILENAME_REGEX}
381      * @param picture           body of the picture. method doesn't close the stream
382      * @param contentType       content type of the image
383      * @throws com.srv4pos.server.api.exceptions.ReferenceNotFoundJsonException if product is not found
384      * @throws com.srv4pos.server.api.exceptions.VersionConflictJsonException   if version doesn't match to seller version
385      * @see ProductServiceSample
386      */
387     public void putPicture(int version, String productIdentifier, String pictureFilename, InputStream picture, String contentType) {
388         requestVoid(
389                 formatPictureUrl(productIdentifier, pictureFilename, null),
390                 HttpMethod.PUT,
391                 url,
392                 credentials.toAuthentication(),
393                 HttpHelper.integerToETag(version),
394                 null,
395                 new InputStreamConnectionWriter(picture),
396                 contentType,
397                 transport
398         );
399     }
400 
401     private String formatPictureUrl(String productIdentifier, String pictureFilename, Integer version) {
402         final String v = version == null ? "current" : version.toString();
403         return format("%s/products/%s/images/%s/%s", credentials.getSellerId(), productIdentifier, v, encodePictureFilename(pictureFilename));
404     }
405 
406     /**
407      * Deletes specified picture.
408      *
409      * @param version           version of seller, if mismatch {@link com.srv4pos.server.api.exceptions.VersionConflictJsonException} will be thrown
410      * @param productIdentifier identifier of the product. must match to {@link Constraints#WINDOWS_FILENAME_REGEX}
411      * @param pictureFilename   picture filename. must match to {@link Constraints#WINDOWS_FILENAME_REGEX}
412      * @throws com.srv4pos.server.api.exceptions.ReferenceNotFoundJsonException if product is not found
413      * @throws com.srv4pos.server.api.exceptions.VersionConflictJsonException   if version doesn't match to seller version
414      * @see ProductServiceSample
415      */
416     public void deletePicture(int version, String productIdentifier, String pictureFilename) {
417         requestVoid(
418                 formatPictureUrl(productIdentifier, pictureFilename, null),
419                 HttpMethod.DELETE,
420                 url,
421                 credentials.toAuthentication(),
422                 HttpHelper.integerToETag(version),
423                 null,
424                 EmptyConnectionWriter.EMPTY_CONNECTION_WRITER,
425                 HttpHelper.CONTENT_TYPE_APPLICATION_JSON,
426                 transport
427         );
428     }
429 
430     /**
431      * Returns stats by products.
432      * @param period filters by date period
433      * @param cashRegisterName filters by cash register name
434      * @return {@link com.srv4pos.server.api.product.ProductsStatsInfo} with stats.
435      * @throws com.srv4pos.server.api.exceptions.TypeMismatchJsonException if {@code period} {@link java.lang.String} isn't convertible to
436      *                                                                     {@link java.util.Date}.
437      */
438     public ProductsStatsInfo stats(String period, String cashRegisterName) {
439 
440         Map<String, String> params = new HashMap<String, String>();
441         if (period != null) {
442             params.put("period", period);
443         }
444         if (cashRegisterName != null) {
445             params.put("cashRegisterName", cashRegisterName);
446         }
447 
448         StringResponse response = requestString(
449                 format("%s/products/stats", credentials.getSellerId()),
450                 HttpMethod.GET,
451                 url,
452                 credentials.toAuthentication(),
453                 null,
454                 params,
455                 EmptyConnectionWriter.EMPTY_CONNECTION_WRITER,
456                 HttpHelper.CONTENT_TYPE_APPLICATION_JSON,
457                 transport
458         );
459         return response == null ? null : ProductsStatsInfo.fromJsonToProductsStatsInfo(response.getContent());
460     }
461 }