7d7f1de5daf4a61bd62319646e395aedc118110e
[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 try {
116 JSONObject postData = JSONUtils.parse(ctx.getRequest().getReader());
117 linkBean.restore(postData);
118 } catch (IOException e) {
119 throw new SqoopException(ServerError.SERVER_0003, "Can't read request content", e);
120 }
121
122 String username = ctx.getUserName();
123
124 // Get link object
125 List<MLink> links = linkBean.getLinks();
126 if (links.size() != 1) {
127 throw new SqoopException(ServerError.SERVER_0003,
128 "Expected one link while parsing JSON request but got " + links.size());
129 }
130
131 MLink postedLink = links.get(0);
132 MConnector mConnector = HandlerUtils.getConnectorFromConnectorName(postedLink.getConnectorName());
133 String oldLinkName = ctx.getLastURLElement();
134
135 // Authorization check
136 if (create) {
137 AuthorizationEngine.createLink(ctx.getUserName(),
138 mConnector.getUniqueName());
139 } else {
140 AuthorizationEngine.updateLink(ctx.getUserName(), mConnector.getUniqueName(),
141 oldLinkName);
142 }
143
144 MLinkConfig linkConfig = ConnectorManager.getInstance()
145 .getConnectorConfigurable(postedLink.getConnectorName()).getLinkConfig();
146 if (!linkConfig.equals(postedLink.getConnectorLinkConfig())) {
147 throw new SqoopException(ServerError.SERVER_0003, "Detected incorrect link config structure");
148 }
149 // if update get the link id from the request URI
150 if (!create) {
151 MLink existingLink = repository.findLink(oldLinkName);
152 if (postedLink.getPersistenceId() == MPersistableEntity.PERSISTANCE_ID_DEFAULT) {
153 postedLink.setPersistenceId(existingLink.getPersistenceId());
154 }
155 }
156 // Associated connector for this link
157 SqoopConnector connector = ConnectorManager.getInstance().getSqoopConnector(
158 postedLink.getConnectorName());
159
160 // Validate user supplied config data
161 ConfigValidationResult connectorLinkConfigValidation = ConfigUtils.validateConfigs(postedLink
162 .getConnectorLinkConfig().getConfigs(), connector.getLinkConfigurationClass());
163 // Return back link validation result bean
164 ValidationResultBean linkValidationBean = new ValidationResultBean(
165 connectorLinkConfigValidation);
166
167 // If we're good enough let's perform the action
168 if (connectorLinkConfigValidation.getStatus().canProceed()) {
169 if (create) {
170 AuditLoggerManager.getInstance().logAuditEvent(ctx.getUserName(),
171 ctx.getRequest().getRemoteAddr(), "create", "link",
172 String.valueOf(postedLink.getPersistenceId()));
173 postedLink.setCreationUser(username);
174 postedLink.setLastUpdateUser(username);
175 repository.createLink(postedLink);
176 linkValidationBean.setName(postedLink.getName());
177 } else {
178 AuditLoggerManager.getInstance().logAuditEvent(ctx.getUserName(),
179 ctx.getRequest().getRemoteAddr(), "update", "link",
180 String.valueOf(postedLink.getPersistenceId()));
181 postedLink.setLastUpdateUser(username);
182 repository.updateLink(postedLink);
183 }
184 }
185
186 return linkValidationBean;
187 }
188
189 private JsonBean getLinks(RequestContext ctx) {
190 String linkName = ctx.getLastURLElement();
191 List<MLink> links;
192 Locale locale = ctx.getAcceptLanguageHeader();
193 Repository repository = RepositoryManager.getInstance().getRepository();
194
195 AuditLoggerManager.getInstance().logAuditEvent(ctx.getUserName(), ctx.getRequest().getRemoteAddr(), "get", "link", linkName);
196
197 if(linkName.equals("all")) { // Return all links (by perhaps only for given connector)
198 String connectorName = ctx.getParameterValue(CONNECTOR_NAME_QUERY_PARAM);
199
200 if(StringUtils.isEmpty(connectorName)) {
201 links = repository.findLinks();
202 } else {
203 if(repository.findConnector(connectorName) == null) {
204 throw new SqoopException(ServerError.SERVER_0006, "Invalid connector: " + connectorName);
205 }
206 links = repository.findLinksForConnector(connectorName);
207 }
208 } else { // Return one specific link with name or id stored in identifier
209 MLink link = HandlerUtils.getLinkFromLinkName(linkName);
210 links = new LinkedList<>();
211 links.add(link);
212 }
213
214 // Authorization check
215 links = AuthorizationEngine.filterResource(ctx.getUserName(), MResource.TYPE.LINK, links);
216
217 // And return resulting links
218 return createLinkBean(links, locale);
219 }
220
221 private LinkBean createLinkBean(List<MLink> links, Locale locale) {
222 LinkBean linkBean = new LinkBean(links);
223 addConnectorConfigBundle(locale, linkBean);
224 return linkBean;
225 }
226
227 private void addConnectorConfigBundle(Locale locale, LinkBean bean) {
228 // Add associated resources into the bean
229 for (MLink link : bean.getLinks()) {
230 String connectorName = link.getConnectorName();
231 if (!bean.hasConnectorConfigBundle(connectorName)) {
232 bean.addConnectorConfigBundle(connectorName, ConnectorManager.getInstance()
233 .getResourceBundle(connectorName, locale));
234 }
235 }
236 }
237
238 private JsonBean enableLink(RequestContext ctx, boolean enabled) {
239 Repository repository = RepositoryManager.getInstance().getRepository();
240 String[] elements = ctx.getUrlElements();
241 String linkName = elements[elements.length - 2];
242 MLink link = HandlerUtils.getLinkFromLinkName(linkName);
243
244 // Authorization check
245 AuthorizationEngine.enableDisableLink(ctx.getUserName(), link.getName());
246
247 repository.enableLink(link.getName(), enabled);
248 return JsonBean.EMPTY_BEAN;
249 }
250 }