SQOOP-2823: Sqoop2: RESTiliency: Remove repetitive try-catch block for accessing...
[sqoop.git] / server / src / main / java / org / apache / sqoop / handler / LinkRequestHandler.java
1 /**
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18 package org.apache.sqoop.handler;
19
20 import java.io.IOException;
21 import java.util.LinkedList;
22 import java.util.List;
23 import java.util.Locale;
24
25 import org.apache.commons.lang.StringUtils;
26 import org.apache.log4j.Logger;
27 import org.apache.sqoop.audit.AuditLoggerManager;
28 import org.apache.sqoop.common.SqoopException;
29 import org.apache.sqoop.connector.ConnectorManager;
30 import org.apache.sqoop.connector.spi.SqoopConnector;
31 import org.apache.sqoop.json.JSONUtils;
32 import org.apache.sqoop.json.JsonBean;
33 import org.apache.sqoop.json.LinkBean;
34 import org.apache.sqoop.json.ValidationResultBean;
35 import org.apache.sqoop.model.*;
36 import org.apache.sqoop.repository.Repository;
37 import org.apache.sqoop.repository.RepositoryManager;
38 import org.apache.sqoop.security.authorization.AuthorizationEngine;
39 import org.apache.sqoop.security.AuthorizationManager;
40 import org.apache.sqoop.server.RequestContext;
41 import org.apache.sqoop.server.RequestHandler;
42 import org.apache.sqoop.server.common.ServerError;
43 import org.apache.sqoop.validation.ConfigValidationResult;
44 import org.json.simple.JSONObject;
45
46 public class LinkRequestHandler implements RequestHandler {
47 private static final long serialVersionUID = 1L;
48
49 private static final Logger LOG = Logger.getLogger(LinkRequestHandler.class);
50
51 static final String ENABLE = "enable";
52 static final String DISABLE = "disable";
53
54 public LinkRequestHandler() {
55 LOG.info("LinkRequestHandler initialized");
56 }
57
58 @Override
59 public JsonBean handleEvent(RequestContext ctx) {
60 switch (ctx.getMethod()) {
61 case GET:
62 return getLinks(ctx);
63 case POST:
64 return createUpdateLink(ctx, true);
65 case PUT:
66 if (ctx.getLastURLElement().equals(ENABLE)) {
67 return enableLink(ctx, true);
68 } else if (ctx.getLastURLElement().equals(DISABLE)) {
69 return enableLink(ctx, false);
70 } else {
71 return createUpdateLink(ctx, false);
72 }
73 case DELETE:
74 return deleteLink(ctx);
75 }
76
77 return null;
78 }
79
80 /**
81 * Delete link in the repository.
82 *
83 * @param ctx Context object
84 * @return Empty bean
85 */
86 private JsonBean deleteLink(RequestContext ctx) {
87 Repository repository = RepositoryManager.getInstance().getRepository();
88 String linkName = ctx.getLastURLElement();
89 // make sure the link exist, otherwise, the exception will be thrown
90 MLink link = HandlerUtils.getLinkFromLinkName(linkName);
91
92 // Authorization check
93 AuthorizationEngine.deleteLink(ctx.getUserName(), link.getName());
94
95 AuditLoggerManager.getInstance().logAuditEvent(ctx.getUserName(),
96 ctx.getRequest().getRemoteAddr(), "delete", "link", link.getName());
97
98 repository.deleteLink(linkName);
99 MResource resource = new MResource(linkName, MResource.TYPE.LINK);
100 AuthorizationManager.getInstance().getAuthorizationHandler().removeResource(resource);
101 return JsonBean.EMPTY_BEAN;
102 }
103
104 /**
105 * Create or Update link in repository.
106 *
107 * @param ctx Context object
108 * @return Validation bean object
109 */
110 private JsonBean createUpdateLink(RequestContext ctx, boolean create) {
111
112 Repository repository = RepositoryManager.getInstance().getRepository();
113
114 LinkBean linkBean = new LinkBean();
115 linkBean.restore(JSONUtils.parse(ctx.getReader()));
116
117 String username = ctx.getUserName();
118
119 // Get link object
120 List<MLink> links = linkBean.getLinks();
121 if (links.size() != 1) {
122 throw new SqoopException(ServerError.SERVER_0003,
123 "Expected one link while parsing JSON request but got " + links.size());
124 }
125
126 MLink postedLink = links.get(0);
127 MConnector mConnector = HandlerUtils.getConnectorFromConnectorName(postedLink.getConnectorName());
128 String oldLinkName = ctx.getLastURLElement();
129
130 // Authorization check
131 if (create) {
132 AuthorizationEngine.createLink(ctx.getUserName(),
133 mConnector.getUniqueName());
134 } else {
135 AuthorizationEngine.updateLink(ctx.getUserName(), mConnector.getUniqueName(),
136 oldLinkName);
137 }
138
139 MLinkConfig linkConfig = ConnectorManager.getInstance()
140 .getConnectorConfigurable(postedLink.getConnectorName()).getLinkConfig();
141 if (!linkConfig.equals(postedLink.getConnectorLinkConfig())) {
142 throw new SqoopException(ServerError.SERVER_0003, "Detected incorrect link config structure");
143 }
144 // if update get the link id from the request URI
145 if (!create) {
146 MLink existingLink = repository.findLink(oldLinkName);
147 if (postedLink.getPersistenceId() == MPersistableEntity.PERSISTANCE_ID_DEFAULT) {
148 postedLink.setPersistenceId(existingLink.getPersistenceId());
149 }
150 }
151 // Associated connector for this link
152 SqoopConnector connector = ConnectorManager.getInstance().getSqoopConnector(
153 postedLink.getConnectorName());
154
155 // Validate user supplied config data
156 ConfigValidationResult connectorLinkConfigValidation = ConfigUtils.validateConfigs(postedLink
157 .getConnectorLinkConfig().getConfigs(), connector.getLinkConfigurationClass());
158 // Return back link validation result bean
159 ValidationResultBean linkValidationBean = new ValidationResultBean(
160 connectorLinkConfigValidation);
161
162 // If we're good enough let's perform the action
163 if (connectorLinkConfigValidation.getStatus().canProceed()) {
164 if (create) {
165 AuditLoggerManager.getInstance().logAuditEvent(ctx.getUserName(),
166 ctx.getRequest().getRemoteAddr(), "create", "link",
167 String.valueOf(postedLink.getPersistenceId()));
168 postedLink.setCreationUser(username);
169 postedLink.setLastUpdateUser(username);
170 repository.createLink(postedLink);
171 linkValidationBean.setName(postedLink.getName());
172 } else {
173 AuditLoggerManager.getInstance().logAuditEvent(ctx.getUserName(),
174 ctx.getRequest().getRemoteAddr(), "update", "link",
175 String.valueOf(postedLink.getPersistenceId()));
176 postedLink.setLastUpdateUser(username);
177 repository.updateLink(postedLink);
178 }
179 }
180
181 return linkValidationBean;
182 }
183
184 private JsonBean getLinks(RequestContext ctx) {
185 String linkName = ctx.getLastURLElement();
186 List<MLink> links;
187 Locale locale = ctx.getAcceptLanguageHeader();
188 Repository repository = RepositoryManager.getInstance().getRepository();
189
190 AuditLoggerManager.getInstance().logAuditEvent(ctx.getUserName(), ctx.getRequest().getRemoteAddr(), "get", "link", linkName);
191
192 if(linkName.equals("all")) { // Return all links (by perhaps only for given connector)
193 String connectorName = ctx.getParameterValue(CONNECTOR_NAME_QUERY_PARAM);
194
195 if(StringUtils.isEmpty(connectorName)) {
196 links = repository.findLinks();
197 } else {
198 if(repository.findConnector(connectorName) == null) {
199 throw new SqoopException(ServerError.SERVER_0006, "Invalid connector: " + connectorName);
200 }
201 links = repository.findLinksForConnector(connectorName);
202 }
203 } else { // Return one specific link with name or id stored in identifier
204 MLink link = HandlerUtils.getLinkFromLinkName(linkName);
205 links = new LinkedList<>();
206 links.add(link);
207 }
208
209 // Authorization check
210 links = AuthorizationEngine.filterResource(ctx.getUserName(), MResource.TYPE.LINK, links);
211
212 // And return resulting links
213 return createLinkBean(links, locale);
214 }
215
216 private LinkBean createLinkBean(List<MLink> links, Locale locale) {
217 LinkBean linkBean = new LinkBean(links);
218 addConnectorConfigBundle(locale, linkBean);
219 return linkBean;
220 }
221
222 private void addConnectorConfigBundle(Locale locale, LinkBean bean) {
223 // Add associated resources into the bean
224 for (MLink link : bean.getLinks()) {
225 String connectorName = link.getConnectorName();
226 if (!bean.hasConnectorConfigBundle(connectorName)) {
227 bean.addConnectorConfigBundle(connectorName, ConnectorManager.getInstance()
228 .getResourceBundle(connectorName, locale));
229 }
230 }
231 }
232
233 private JsonBean enableLink(RequestContext ctx, boolean enabled) {
234 Repository repository = RepositoryManager.getInstance().getRepository();
235 String[] elements = ctx.getUrlElements();
236 String linkName = elements[elements.length - 2];
237 MLink link = HandlerUtils.getLinkFromLinkName(linkName);
238
239 // Authorization check
240 AuthorizationEngine.enableDisableLink(ctx.getUserName(), link.getName());
241
242 repository.enableLink(link.getName(), enabled);
243 return JsonBean.EMPTY_BEAN;
244 }
245 }