Add creation of metadata file on subscriber
[dmaap/datarouter.git] / datarouter-subscriber / src / main / java / org / onap / dmaap / datarouter / subscriber / SampleSubscriberServlet.java
1 /*******************************************************************************
2  * ============LICENSE_START==================================================
3  * * org.onap.dmaap
4  * * ===========================================================================
5  * * Copyright © 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  * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
21  * *
22  ******************************************************************************/
23 package org.onap.dmaap.datarouter.subscriber;
24
25 import org.apache.commons.codec.binary.Base64;
26 import org.apache.log4j.Logger;
27
28 import javax.servlet.http.HttpServlet;
29 import javax.servlet.http.HttpServletRequest;
30 import javax.servlet.http.HttpServletResponse;
31 import java.io.*;
32 import java.net.URLEncoder;
33 import java.nio.file.Files;
34 import java.nio.file.Paths;
35 import java.nio.file.StandardCopyOption;
36
37 public class SampleSubscriberServlet extends HttpServlet {
38
39   private static Logger logger =
40       Logger.getLogger("org.onap.dmaap.datarouter.subscriber.SampleSubscriberServlet");
41   private static String outputDirectory;
42   private static String basicAuth;
43
44   /**
45    * Configure the SampleSubscriberServlet.
46    *
47    * <ul>
48    *   <li>Login - The login expected in the Authorization header (default "LOGIN").
49    *   <li>Password - The password expected in the Authorization header (default "PASSWORD").
50    *   <li>outputDirectory - The directory where files are placed (default
51    *       "/opt/app/subscriber/delivery").
52    * </ul>
53    */
54   @Override
55   public void init() {
56     SubscriberProps props = SubscriberProps.getInstance();
57     String login = props.getValue("org.onap.dmaap.datarouter.subscriber.auth.user", "LOGIN");
58     String password =
59         props.getValue("org.onap.dmaap.datarouter.subscriber.auth.password", "PASSWORD");
60     outputDirectory =
61         props.getValue(
62             "org.onap.dmaap.datarouter.subscriber.delivery.dir", "/opt/app/subscriber/delivery");
63     try {
64       Files.createDirectory(Paths.get(outputDirectory));
65     } catch (IOException e) {
66       logger.info("SubServlet: Failed to create delivery dir: " + e.getMessage());
67     }
68     basicAuth = "Basic " + Base64.encodeBase64String((login + ":" + password).getBytes());
69   }
70
71   @Override
72   protected void doPut(HttpServletRequest req, HttpServletResponse resp) {
73     try {
74       common(req, resp, false);
75     } catch (IOException e) {
76       logger.info(
77           "SampleSubServlet: Failed to doPut: " + req.getRemoteAddr() + " : " + req.getPathInfo(),
78           e);
79     }
80   }
81
82   @Override
83   protected void doDelete(HttpServletRequest req, HttpServletResponse resp) {
84     try {
85       common(req, resp, true);
86     } catch (IOException e) {
87       logger.info(
88           "SampleSubServlet: Failed to doDelete: "
89               + req.getRemoteAddr()
90               + " : "
91               + req.getPathInfo(),
92           e);
93     }
94   }
95   /**
96    * Process a PUT or DELETE request.
97    *
98    * <ol>
99    *   <li>Verify that the request contains an Authorization header or else UNAUTHORIZED.
100    *   <li>Verify that the Authorization header matches the configured Login and Password or else
101    *       FORBIDDEN.
102    *   <li>If the request is PUT, store the message body as a file in the configured outputDirectory
103    *       directory protecting against evil characters in the received FileID. The file is created
104    *       initially with its name prefixed with a ".", and once it is complete, it is renamed to
105    *       remove the leading "." character.
106    *   <li>If the request is DELETE, instead delete the file (if it exists) from the configured
107    *       outputDirectory directory.
108    *   <li>Respond with NO_CONTENT.
109    * </ol>
110    */
111   private void common(HttpServletRequest req, HttpServletResponse resp, boolean isdelete)
112       throws IOException {
113     String authHeader = req.getHeader("Authorization");
114     if (authHeader == null) {
115       logger.info(
116           "SampleSubServlet: Rejecting request with no Authorization header from "
117               + req.getRemoteAddr()
118               + ": "
119               + req.getPathInfo());
120       resp.sendError(HttpServletResponse.SC_UNAUTHORIZED);
121       return;
122     }
123     if (!basicAuth.equals(authHeader)) {
124       logger.info(
125           "SampleSubServlet: Rejecting request with incorrect Authorization header from "
126               + req.getRemoteAddr()
127               + ": "
128               + req.getPathInfo());
129       resp.sendError(HttpServletResponse.SC_FORBIDDEN);
130       return;
131     }
132     String fileid = req.getPathInfo();
133     fileid = fileid.substring(fileid.lastIndexOf('/') + 1);
134     String queryString = req.getQueryString();
135     if (queryString != null) {
136       fileid = fileid + "?" + queryString;
137     }
138     String publishid = req.getHeader("X-ATT-DR-PUBLISH-ID");
139     String filename =
140         URLEncoder.encode(fileid, "UTF-8").replaceAll("^\\.", "%2E").replaceAll("\\*", "%2A");
141     String fullPath = outputDirectory + "/" + filename;
142     String tmpPath = outputDirectory + "/." + filename;
143     String fullMetaDataPath = outputDirectory + "/" + filename + ".M";
144     String tmpMetaDataPath = outputDirectory + "/." + filename + ".M";
145     try {
146       if (isdelete) {
147         Files.deleteIfExists(Paths.get(fullPath));
148         Files.deleteIfExists(Paths.get(fullMetaDataPath));
149         logger.info(
150             "SampleSubServlet: Received delete for file id "
151                 + fileid
152                 + " from "
153                 + req.getRemoteAddr()
154                 + " publish id "
155                 + publishid
156                 + " as "
157                 + fullPath);
158       } else {
159         new File(tmpPath).createNewFile();
160         new File(tmpMetaDataPath).createNewFile();
161         try (InputStream is = req.getInputStream();
162             OutputStream os = new FileOutputStream(tmpPath)) {
163           byte[] buf = new byte[65536];
164           int i;
165           while ((i = is.read(buf)) > 0) {
166             os.write(buf, 0, i);
167           }
168         }
169         Files.move(Paths.get(tmpPath), Paths.get(fullPath), StandardCopyOption.REPLACE_EXISTING);
170         try (PrintWriter writer = new PrintWriter(new FileOutputStream(tmpMetaDataPath))) {
171           String metaData = req.getHeader("X-ATT-DR-META");
172           writer.print(metaData);
173         }
174         Files.move(Paths.get(tmpMetaDataPath), Paths.get(fullMetaDataPath), StandardCopyOption.REPLACE_EXISTING);
175         logger.info(
176             "SampleSubServlet: Received file id "
177                 + fileid
178                 + " from "
179                 + req.getRemoteAddr()
180                 + " publish id "
181                 + publishid
182                 + " as "
183                 + fullPath);
184         resp.setStatus(HttpServletResponse.SC_NO_CONTENT);
185       }
186       resp.setStatus(HttpServletResponse.SC_NO_CONTENT);
187     } catch (IOException ioe) {
188       Files.deleteIfExists(Paths.get(tmpPath));
189       Files.deleteIfExists(Paths.get(tmpMetaDataPath));
190       logger.info(
191           "SampleSubServlet: Failed to process file "
192               + fullPath
193               + " from "
194               + req.getRemoteAddr()
195               + ": "
196               + req.getPathInfo());
197       throw ioe;
198     }
199   }
200 }