| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * <p> |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * <p> |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.hadoop.ozone.web.ozShell; |
| |
| import java.io.IOException; |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| |
| import org.apache.hadoop.hdds.conf.OzoneConfiguration; |
| import org.apache.hadoop.ozone.OmUtils; |
| import org.apache.hadoop.ozone.client.OzoneClient; |
| import org.apache.hadoop.ozone.client.OzoneClientException; |
| import org.apache.hadoop.ozone.client.OzoneClientFactory; |
| |
| import static org.apache.hadoop.ozone.OzoneConsts.OZONE_HTTP_SCHEME; |
| import static org.apache.hadoop.ozone.OzoneConsts.OZONE_RPC_SCHEME; |
| import org.apache.http.client.utils.URIBuilder; |
| |
| /** |
| * Address of an ozone object for ozone shell. |
| */ |
| public class OzoneAddress { |
| |
| private static final String EMPTY_HOST = "___DEFAULT___"; |
| |
| private URI ozoneURI; |
| |
| private String volumeName = ""; |
| |
| private String bucketName = ""; |
| |
| private String keyName = ""; |
| |
| public OzoneAddress() throws OzoneClientException { |
| this("o3:///"); |
| } |
| |
| public OzoneAddress(String address) |
| throws OzoneClientException { |
| if (address == null || address.equals("")) { |
| address = OZONE_RPC_SCHEME + ":///"; |
| } |
| this.ozoneURI = parseURI(address); |
| String path = this.ozoneURI.getPath(); |
| |
| path = path.replaceAll("^/+", ""); |
| |
| int sep1 = path.indexOf('/'); |
| int sep2 = path.indexOf('/', sep1 + 1); |
| |
| if (sep1 == -1) { |
| volumeName = path; |
| } else { |
| //we have vol/bucket |
| volumeName = path.substring(0, sep1); |
| if (sep2 == -1) { |
| bucketName = path.substring(sep1 + 1); |
| } else { |
| //we have vol/bucket/key/.../... |
| bucketName = path.substring(sep1 + 1, sep2); |
| keyName = path.substring(sep2 + 1); |
| } |
| } |
| |
| } |
| |
| public OzoneClient createClient(OzoneConfiguration conf) |
| throws IOException, OzoneClientException { |
| OzoneClient client; |
| String scheme = ozoneURI.getScheme(); |
| if (ozoneURI.getScheme() == null || scheme.isEmpty()) { |
| scheme = OZONE_RPC_SCHEME; |
| } |
| if (scheme.equals(OZONE_HTTP_SCHEME)) { |
| throw new UnsupportedOperationException( |
| "REST schema is not supported any more. Please use AWS S3 protocol " |
| + "if you need REST interface."); |
| } else if (scheme.equals(OZONE_RPC_SCHEME)) { |
| if (ozoneURI.getHost() != null && !ozoneURI.getAuthority() |
| .equals(EMPTY_HOST)) { |
| if (OmUtils.isOmHAServiceId(conf, ozoneURI.getHost())) { |
| // When host is an HA service ID |
| if (ozoneURI.getPort() != -1) { |
| throw new OzoneClientException( |
| "Port " + ozoneURI.getPort() + " specified in URI but host '" |
| + ozoneURI.getHost() + "' is a logical (HA) OzoneManager " |
| + "and does not use port information."); |
| } |
| client = OzoneClientFactory.getRpcClient(ozoneURI.getHost(), conf); |
| } else if (ozoneURI.getPort() == -1) { |
| client = OzoneClientFactory.getRpcClient(ozoneURI.getHost()); |
| } else { |
| client = OzoneClientFactory |
| .getRpcClient(ozoneURI.getHost(), ozoneURI.getPort(), conf); |
| } |
| } else { |
| // When host is not specified |
| if (OmUtils.isServiceIdsDefined(conf)) { |
| throw new OzoneClientException("Service ID or host name must not" |
| + " be omitted when ozone.om.service.ids is defined."); |
| } |
| client = OzoneClientFactory.getRpcClient(conf); |
| } |
| } else { |
| throw new OzoneClientException( |
| "Invalid URI, unknown protocol scheme: " + scheme); |
| } |
| return client; |
| } |
| |
| /** |
| * verifies user provided URI. |
| * |
| * @param uri - UriString |
| * @return URI |
| * @throws URISyntaxException |
| * @throws OzoneException |
| */ |
| protected URI parseURI(String uri) |
| throws OzoneClientException { |
| if ((uri == null) || uri.isEmpty()) { |
| throw new OzoneClientException( |
| "Ozone URI is needed to execute this command."); |
| } |
| URIBuilder uriBuilder = new URIBuilder(stringToUri(uri)); |
| if (uriBuilder.getPort() == 0) { |
| uriBuilder.setPort(Shell.DEFAULT_OZONE_PORT); |
| } |
| |
| try { |
| return uriBuilder.build(); |
| } catch (URISyntaxException e) { |
| throw new OzoneClientException("Invalid URI: " + ozoneURI, e); |
| } |
| } |
| |
| /** |
| * Construct a URI from a String with unescaped special characters |
| * that have non-standard semantics. e.g. /, ?, #. A custom parsing |
| * is needed to prevent misbehavior. |
| * |
| * @param pathString The input path in string form |
| * @return URI |
| */ |
| private static URI stringToUri(String pathString) { |
| // parse uri components |
| String scheme = null; |
| String authority = null; |
| int start = 0; |
| |
| // parse uri scheme, if any |
| int colon = pathString.indexOf(':'); |
| int slash = pathString.indexOf('/'); |
| if (colon > 0 && (slash == colon + 1)) { |
| // has a non zero-length scheme |
| scheme = pathString.substring(0, colon); |
| start = colon + 1; |
| } |
| |
| // parse uri authority, if any |
| if (pathString.startsWith("//", start) && |
| (pathString.length() - start > 2)) { |
| start += 2; |
| int nextSlash = pathString.indexOf('/', start); |
| int authEnd = nextSlash > 0 ? nextSlash : pathString.length(); |
| authority = pathString.substring(start, authEnd); |
| start = authEnd; |
| } |
| // uri path is the rest of the string. ? or # are not interpreted, |
| // but any occurrence of them will be quoted by the URI ctor. |
| String path = pathString.substring(start, pathString.length()); |
| |
| // add leading slash to the path, if it does not exist |
| int firstSlash = path.indexOf('/'); |
| if(firstSlash != 0) { |
| path = "/" + path; |
| } |
| |
| if (authority == null || authority.equals("")) { |
| authority = EMPTY_HOST; |
| } |
| // Construct the URI |
| try { |
| return new URI(scheme, authority, path, null, null); |
| } catch (URISyntaxException e) { |
| throw new IllegalArgumentException(e); |
| } |
| } |
| |
| public String getVolumeName() { |
| return volumeName; |
| } |
| |
| public String getBucketName() { |
| return bucketName; |
| } |
| |
| public String getKeyName() { |
| return keyName; |
| } |
| |
| public void ensureBucketAddress() throws OzoneClientException { |
| if (keyName.length() > 0) { |
| throw new OzoneClientException( |
| "Invalid bucket name. Delimiters (/) not allowed in bucket name"); |
| } else if (volumeName.length() == 0) { |
| throw new OzoneClientException( |
| "Volume name is required."); |
| } else if (bucketName.length() == 0) { |
| throw new OzoneClientException( |
| "Bucket name is required."); |
| } |
| } |
| |
| public void ensureKeyAddress() throws OzoneClientException { |
| if (keyName.length() == 0) { |
| throw new OzoneClientException( |
| "Key name is missing."); |
| } else if (volumeName.length() == 0) { |
| throw new OzoneClientException( |
| "Volume name is missing"); |
| } else if (bucketName.length() == 0) { |
| throw new OzoneClientException( |
| "Bucket name is missing"); |
| } |
| } |
| |
| public void ensureVolumeAddress() throws OzoneClientException { |
| if (keyName.length() != 0) { |
| throw new OzoneClientException( |
| "Invalid volume name. Delimiters (/) not allowed in volume name"); |
| } else if (volumeName.length() == 0) { |
| throw new OzoneClientException( |
| "Volume name is required"); |
| } else if (bucketName.length() != 0) { |
| throw new OzoneClientException( |
| "Invalid volume name. Delimiters (/) not allowed in volume name"); |
| } |
| } |
| |
| public void ensureRootAddress() throws OzoneClientException { |
| if (keyName.length() != 0 || bucketName.length() != 0 |
| || volumeName.length() != 0) { |
| throw new OzoneClientException( |
| "Invalid URI. Volume/bucket/key elements should not been used"); |
| } |
| } |
| } |