74360e8024c395f287d1624df51dbd1c55cb36bf
[policy/drools-pdp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * policy-endpoints
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20 package org.openecomp.policy.drools.http.server.internal;
21
22 import org.eclipse.jetty.security.ConstraintMapping;
23 import org.eclipse.jetty.security.ConstraintSecurityHandler;
24 import org.eclipse.jetty.security.HashLoginService;
25 import org.eclipse.jetty.security.authentication.BasicAuthenticator;
26 import org.eclipse.jetty.server.Server;
27 import org.eclipse.jetty.server.ServerConnector;
28 import org.eclipse.jetty.servlet.ServletContextHandler;
29 import org.eclipse.jetty.util.security.Constraint;
30 import org.eclipse.jetty.util.security.Credential;
31
32 import org.openecomp.policy.common.logging.eelf.MessageCodes;
33 import org.openecomp.policy.common.logging.flexlogger.FlexLogger;
34 import org.openecomp.policy.common.logging.flexlogger.Logger;
35 import org.openecomp.policy.drools.http.server.HttpServletServer;
36
37 import com.fasterxml.jackson.annotation.JsonIgnore;
38
39 /**
40  * Http Server implementation using Embedded Jetty
41  */
42 public abstract class JettyServletServer implements HttpServletServer, Runnable {
43         
44         private static Logger logger = FlexLogger.getLogger(JettyServletServer.class);
45
46         protected final String name;
47
48         protected final String host;
49         protected final int port;
50         
51         protected String user;
52         protected String password;
53         
54         protected final String contextPath;
55         
56         protected final Server jettyServer;
57         protected final ServletContextHandler context;
58         protected final ServerConnector connector;
59         
60         protected volatile Thread jettyThread;
61         
62         protected Object startCondition = new Object();
63         
64         public JettyServletServer(String name, String host, int port, String contextPath) 
65                    throws IllegalArgumentException {
66                         
67                 if (name == null || name.isEmpty())
68                         name = "http-" + port;
69                 
70                 if (port <= 0 && port >= 65535)
71                         throw new IllegalArgumentException("Invalid Port provided: " + port);
72                 
73                 if (host == null || host.isEmpty())
74                         host = "localhost";
75                 
76                 if (contextPath == null || contextPath.isEmpty())
77                         contextPath = "/";
78                 
79                 this.name = name;
80                 
81                 this.host = host;
82                 this.port = port;
83
84                 this.contextPath = contextPath;
85                 
86         this.context = new ServletContextHandler(ServletContextHandler.SESSIONS);
87         this.context.setContextPath(contextPath);
88         
89         this.jettyServer = new Server();
90         
91         this.connector = new ServerConnector(this.jettyServer);
92         this.connector.setName(name);
93         this.connector.setReuseAddress(true);
94         this.connector.setPort(port);
95         this.connector.setHost(host);    
96         
97         this.jettyServer.addConnector(this.connector);       
98         this.jettyServer.setHandler(context);
99         }
100         
101         /**
102          * {@inheritDoc}
103          */
104         @Override
105         public void setBasicAuthentication(String user, String password, String servletPath) {
106         if (user == null || user.isEmpty() || password == null || password.isEmpty()) 
107                 throw new IllegalArgumentException("Missing user and/or password");
108         
109         if (servletPath == null || servletPath.isEmpty())
110                 servletPath = "/*";
111                         
112         HashLoginService hashLoginService = new HashLoginService();
113         hashLoginService.putUser(user, 
114                                         Credential.getCredential(password), 
115                                         new String[] {"user"});
116         hashLoginService.setName(this.connector.getName() + "-login-service");
117         
118         Constraint constraint = new Constraint();
119         constraint.setName(Constraint.__BASIC_AUTH);
120         constraint.setRoles(new String[]{"user"});
121         constraint.setAuthenticate(true);
122          
123         ConstraintMapping constraintMapping = new ConstraintMapping();
124         constraintMapping.setConstraint(constraint);
125         constraintMapping.setPathSpec(servletPath);
126         
127         ConstraintSecurityHandler securityHandler = new ConstraintSecurityHandler();
128         securityHandler.setAuthenticator(new BasicAuthenticator());
129         securityHandler.setRealmName(this.connector.getName() + "-realm");
130         securityHandler.addConstraintMapping(constraintMapping);
131         securityHandler.setLoginService(hashLoginService);              
132         
133         this.context.setSecurityHandler(securityHandler);
134         
135                 this.user = user;
136                 this.password = password;
137         }
138         
139         /**
140          * Jetty Server Execution
141          */
142         @Override
143         public void run() {
144         try {           
145                 if (logger.isInfoEnabled())
146                         logger.info(this + " STARTING " + this.jettyServer.dump());
147                 
148             this.jettyServer.start();
149             
150                 synchronized(this.startCondition) {
151                         this.startCondition.notifyAll();
152                 }
153                 
154             this.jettyServer.join();
155         } catch (Exception e) {
156                         logger.warn(MessageCodes.EXCEPTION_ERROR, e,  
157                             "Error found while running management server", this.toString());
158                 } 
159         }
160         
161         @Override
162         public boolean waitedStart(long maxWaitTime) throws IllegalArgumentException {
163                 
164                 if (maxWaitTime < 0)
165                         throw new IllegalArgumentException("max-wait-time cannot be negative");
166                 
167                 long pendingWaitTime = maxWaitTime;
168                 
169                 if (!this.start())
170                         return false;
171                 
172                 synchronized (this.startCondition) {
173                         
174                         while (!this.jettyServer.isRunning()) {
175                                 try {
176                                         long startTs = System.currentTimeMillis();
177                                         
178                                         this.startCondition.wait(pendingWaitTime);
179                                         
180                                         if (maxWaitTime == 0)
181                                                 /* spurious notification */
182                                                 continue;
183                                         
184                                         long endTs = System.currentTimeMillis();
185                                         pendingWaitTime = pendingWaitTime - (endTs - startTs);
186                                         
187                                         if (logger.isInfoEnabled())
188                                                 logger.info(this + "Pending time is " + pendingWaitTime + 
189                                                                     " ms.");
190                                         
191                                         if (pendingWaitTime <= 0)
192                                                 return false;
193                                         
194                                 } catch (InterruptedException e) {
195                                         logger.warn("waited-start has been interrupted");
196                                         return false;                   
197                                 }
198                         }
199                         
200                         return (this.jettyServer.isRunning());
201                 }
202         }
203
204         /**
205          * {@inheritDoc}
206          */
207         @Override
208         public boolean start() throws IllegalStateException {
209                 if (logger.isDebugEnabled())
210                         logger.debug(this + "START");
211                 
212                 synchronized(this) {                    
213                         if (jettyThread == null || 
214                                 !this.jettyThread.isAlive()) {
215                                 
216                                 this.jettyThread = new Thread(this);
217                                 this.jettyThread.setName(this.name + "-" + this.port);
218                                 this.jettyThread.start();
219                         }
220                 }
221                 
222                 return true;
223         }
224
225         /**
226          * {@inheritDoc}
227          */
228         @Override
229         public boolean stop() throws IllegalStateException {
230                 logger.info(this + "STOP");
231                 
232                 synchronized(this) {
233                         if (jettyThread == null) {
234                                 return true;
235                         } 
236                         
237                         if (!jettyThread.isAlive()) {
238                                 this.jettyThread = null;
239                         } 
240                         
241                         try {
242                                 this.connector.stop();
243                         } catch (Exception e) {
244                                 logger.error(MessageCodes.EXCEPTION_ERROR, e,  
245                                            "Error while stopping management server", this.toString());
246                                 e.printStackTrace();
247                         }
248                         
249                         try {
250                                 this.jettyServer.stop();
251                         } catch (Exception e) {
252                                 logger.error(MessageCodes.EXCEPTION_ERROR, e,  
253                                                            "Error while stopping management server", this.toString());
254                                 return false;
255                         }
256                         
257                         Thread.yield();
258                 }
259
260                 return true;
261         }
262
263         /**
264          * {@inheritDoc}
265          */
266         @Override
267         public void shutdown() throws IllegalStateException {
268                 logger.info(this + "SHUTDOWN");
269                 
270                 this.stop();
271                 
272                 if (this.jettyThread == null)
273                         return;
274                 
275                 Thread jettyThreadCopy = this.jettyThread;
276
277                 if (jettyThreadCopy.isAlive()) {
278                         try {
279                                 jettyThreadCopy.join(1000L);
280                         } catch (InterruptedException e) {
281                                 logger.warn(MessageCodes.EXCEPTION_ERROR, e,  
282                                                   "Error while shutting down management server", this.toString());
283                         }
284                         if (!jettyThreadCopy.isInterrupted()) {
285                                 try {
286                                         jettyThreadCopy.interrupt();
287                                 } catch(Exception e) {
288                                         // do nothing
289                                         logger.warn("exception while shutting down (OK)");
290                                 }
291                         }
292                 }
293                 
294                 this.jettyServer.destroy();
295         }
296
297         /**
298          * {@inheritDoc}
299          */
300         @Override
301         public boolean isAlive() {
302                 if (this.jettyThread != null)
303                         return this.jettyThread.isAlive();
304                 
305                 return false;
306         }
307
308         @Override
309         public int getPort() {
310                 return this.port;
311         }
312
313         /**
314          * @return the name
315          */
316         public String getName() {
317                 return name;
318         }
319
320         /**
321          * @return the host
322          */
323         public String getHost() {
324                 return host;
325         }
326
327         /**
328          * @return the user
329          */
330         public String getUser() {
331                 return user;
332         }
333
334         /**
335          * @return the password
336          */
337         @JsonIgnore
338         public String getPassword() {
339                 return password;
340         }
341
342         @Override
343         public String toString() {
344                 StringBuilder builder = new StringBuilder();
345                 builder.append("JettyServer [name=").append(name).append(", host=").append(host).append(", port=").append(port)
346                                 .append(", user=").append(user).append(", password=").append((password != null)).append(", contextPath=")
347                                 .append(contextPath).append(", jettyServer=").append(jettyServer).append(", context=").append(this.context)
348                                 .append(", connector=").append(connector).append(", jettyThread=").append(jettyThread)
349                                 .append("]");
350                 return builder.toString();
351         }
352
353 }