View Javadoc
1   /*
2    * This file is part of ***  M y C o R e  ***
3    * See http://www.mycore.de/ for details.
4    *
5    * MyCoRe is free software: you can redistribute it and/or modify
6    * it under the terms of the GNU General Public License as published by
7    * the Free Software Foundation, either version 3 of the License, or
8    * (at your option) any later version.
9    *
10   * MyCoRe is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License
16   * along with MyCoRe.  If not, see <http://www.gnu.org/licenses/>.
17   */
18  package org.mycore.services.queuedjob;
19  
20  import java.io.OutputStream;
21  import java.io.PrintStream;
22  import java.nio.charset.StandardCharsets;
23  import java.util.ArrayList;
24  import java.util.Date;
25  import java.util.List;
26  import java.util.Locale;
27  import java.util.stream.Collectors;
28  import java.util.stream.StreamSupport;
29  
30  import org.mycore.frontend.jersey.filter.access.MCRRestrictedAccess;
31  
32  import jakarta.inject.Singleton;
33  import jakarta.ws.rs.GET;
34  import jakarta.ws.rs.Path;
35  import jakarta.ws.rs.PathParam;
36  import jakarta.ws.rs.Produces;
37  import jakarta.ws.rs.core.MediaType;
38  import jakarta.ws.rs.core.Response;
39  import jakarta.ws.rs.core.StreamingOutput;
40  import jakarta.xml.bind.annotation.XmlAttribute;
41  import jakarta.xml.bind.annotation.XmlElement;
42  import jakarta.xml.bind.annotation.XmlRootElement;
43  import jakarta.xml.bind.annotation.XmlValue;
44  
45  /**
46   * @author Ren\u00E9 Adler (eagle)
47   *
48   */
49  @Path("jobqueue")
50  @Singleton
51  public class MCRJobQueueResource {
52  
53      @GET()
54      @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
55      @MCRRestrictedAccess(MCRJobQueuePermission.class)
56      public Response listJSON() {
57          try {
58              Queues queuesEntity = new Queues();
59              queuesEntity.addAll(
60                  MCRJobQueue.INSTANCES.keySet().stream().map(Queue::new).collect(Collectors.toList()));
61  
62              return Response
63                  .ok()
64                  .status(Response.Status.OK)
65                  .entity(queuesEntity)
66                  .build();
67          } catch (Exception e) {
68              final StreamingOutput so = (OutputStream os) -> e
69                  .printStackTrace(new PrintStream(os, false, StandardCharsets.UTF_8.name()));
70              return Response
71                  .status(Response.Status.INTERNAL_SERVER_ERROR)
72                  .type(MediaType.TEXT_PLAIN_TYPE)
73                  .entity(so)
74                  .build();
75          }
76      }
77  
78      @GET()
79      @Path("{name:.+}")
80      @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
81      @MCRRestrictedAccess(MCRJobQueuePermission.class)
82      public Response queueJSON(@PathParam("name") String name) {
83          try {
84              Queue queue = MCRJobQueue.INSTANCES.entrySet().stream().filter(e -> e.getKey().equals(name)).findFirst()
85                  .map(e -> {
86                      Queue q = new Queue(e.getKey());
87  
88                      MCRJobQueue jq = e.getValue();
89                      Iterable<MCRJob> iterable = () -> jq.iterator(null);
90                      q.jobs = StreamSupport.stream(iterable.spliterator(), false).map(Job::new)
91                          .collect(Collectors.toList());
92  
93                      return q;
94                  }).orElse(null);
95  
96              return Response
97                  .ok()
98                  .status(Response.Status.OK)
99                  .entity(queue)
100                 .build();
101         } catch (Exception e) {
102             final StreamingOutput so = (OutputStream os) -> e
103                 .printStackTrace(new PrintStream(os, false, StandardCharsets.UTF_8.name()));
104             return Response
105                 .status(Response.Status.INTERNAL_SERVER_ERROR)
106                 .type(MediaType.TEXT_PLAIN_TYPE)
107                 .entity(so)
108                 .build();
109         }
110     }
111 
112     @XmlRootElement(name = "queues")
113     static class Queues {
114         @XmlElement(name = "queue")
115         List<Queue> queues;
116 
117         void add(Queue queue) {
118             if (queues == null) {
119                 queues = new ArrayList<>();
120             }
121 
122             queues.add(queue);
123         }
124 
125         void addAll(List<Queue> queues) {
126             if (this.queues == null) {
127                 this.queues = new ArrayList<>();
128             }
129 
130             this.queues.addAll(queues);
131         }
132     }
133 
134     @XmlRootElement(name = "queue")
135     static class Queue {
136         @XmlAttribute
137         String name;
138 
139         @XmlElement(name = "job")
140         List<Job> jobs;
141 
142         Queue() {
143         }
144 
145         Queue(String name) {
146             this.name = name;
147         }
148     }
149 
150     @XmlRootElement(name = "job")
151     static class Job {
152         @XmlAttribute
153         long id;
154 
155         @XmlAttribute
156         String status;
157 
158         @XmlElement(name = "date")
159         List<TypedDate> dates;
160 
161         @XmlElement(name = "parameter")
162         List<Parameter> parameters;
163 
164         Job() {
165         }
166 
167         Job(MCRJob job) {
168             this.id = job.getId();
169             this.status = job.getStatus().toString().toLowerCase(Locale.ROOT);
170 
171             List<TypedDate> dates = new ArrayList<>();
172             if (job.getAdded() != null) {
173                 dates.add(new TypedDate("added", job.getAdded()));
174             }
175             if (job.getStart() != null) {
176                 dates.add(new TypedDate("start", job.getStart()));
177             }
178             if (job.getFinished() != null) {
179                 dates.add(new TypedDate("finished", job.getFinished()));
180             }
181 
182             this.parameters = job.getParameters().entrySet().stream().map(e -> new Parameter(e.getKey(), e.getValue()))
183                 .collect(Collectors.toList());
184 
185             if (!dates.isEmpty()) {
186                 this.dates = dates;
187             }
188         }
189     }
190 
191     @XmlRootElement(name = "date")
192     static class TypedDate {
193         @XmlAttribute
194         String type;
195 
196         @XmlValue
197         Date date;
198 
199         TypedDate() {
200         }
201 
202         TypedDate(String type, Date date) {
203             this.type = type;
204             this.date = date;
205         }
206     }
207 
208     @XmlRootElement(name = "parameter")
209     static class Parameter {
210         @XmlAttribute
211         String name;
212 
213         @XmlValue
214         String value;
215 
216         Parameter() {
217         }
218 
219         Parameter(String name, String value) {
220             this.name = name;
221             this.value = value;
222         }
223     }
224 
225 }