/*
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.ignite.internal.processors.hadoop.igfs;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.IgniteFileSystem;
import org.apache.ignite.igfs.IgfsIpcEndpointConfiguration;
import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.lang.IgniteBiTuple;
import org.jetbrains.annotations.Nullable;
/**
* IGFS endpoint abstraction.
*/
public class HadoopIgfsEndpoint {
/** Guard ensuring that warning about grid name is printed only once. */
private static final AtomicBoolean LOG_WARN_GUARD = new AtomicBoolean();
/** Logger. */
private static final Log LOG = LogFactory.getLog(HadoopIgfsEndpoint.class);
/** Localhost. */
public static final String LOCALHOST = "127.0.0.1";
/** IGFS name. */
private final String igfsName;
/** Host. */
private final String host;
/** Port. */
private final int port;
/**
* Normalize IGFS URI.
*
* @param uri URI.
* @return Normalized URI.
* @throws IOException If failed.
*/
public static URI normalize(URI uri) throws IOException {
try {
if (!F.eq(IgniteFileSystem.IGFS_SCHEME, uri.getScheme()))
throw new IOException("Failed to normalize UIR because it has non IGFS scheme: " + uri);
HadoopIgfsEndpoint endpoint = new HadoopIgfsEndpoint(uri.getAuthority());
StringBuilder sb = new StringBuilder();
if (endpoint.igfs() != null)
sb.append(endpoint.igfs());
return new URI(uri.getScheme(), sb.length() != 0 ? sb.toString() : null, endpoint.host(), endpoint.port(),
uri.getPath(), uri.getQuery(), uri.getFragment());
}
catch (URISyntaxException | IgniteCheckedException e) {
throw new IOException("Failed to normalize URI: " + uri, e);
}
}
/**
* Constructor.
*
* @param connStr Connection string.
* @throws IgniteCheckedException If failed to parse connection string.
*/
public HadoopIgfsEndpoint(@Nullable String connStr) throws IgniteCheckedException {
if (connStr == null)
connStr = "";
String[] tokens = connStr.split("@", -1);
IgniteBiTuple<String, Integer> hostPort;
if (tokens.length == 1) {
igfsName = null;
hostPort = hostPort(connStr, connStr);
}
else if (tokens.length == 2) {
String authStr = tokens[0];
if (authStr.isEmpty())
igfsName = null;
else {
String[] authTokens = authStr.split(":", -1);
igfsName = F.isEmpty(authTokens[0]) ? null : authTokens[0];
if (authTokens.length == 2) {
if (!LOG_WARN_GUARD.get() && LOG_WARN_GUARD.compareAndSet(false, true))
LOG.warn("Grid name in IGFS connection string is deprecated and will be ignored: " + connStr);
}
else if (authTokens.length > 2)
throw new IgniteCheckedException("Invalid connection string format: " + connStr);
}
hostPort = hostPort(connStr, tokens[1]);
}
else
throw new IgniteCheckedException("Invalid connection string format: " + connStr);
if (igfsName == null)
throw new IgniteCheckedException("Invalid connection string format (IGFS name cannot be empty): "
+ connStr);
host = hostPort.get1();
assert hostPort.get2() != null;
port = hostPort.get2();
}
/**
* Parse host and port.
*
* @param connStr Full connection string.
* @param hostPortStr Host/port connection string part.
* @return Tuple with host and port.
* @throws IgniteCheckedException If failed to parse connection string.
*/
private IgniteBiTuple<String, Integer> hostPort(String connStr, String hostPortStr) throws IgniteCheckedException {
String[] tokens = hostPortStr.split(":", -1);
String host = tokens[0];
if (F.isEmpty(host))
host = LOCALHOST;
int port;
if (tokens.length == 1)
port = IgfsIpcEndpointConfiguration.DFLT_PORT;
else if (tokens.length == 2) {
String portStr = tokens[1];
try {
port = Integer.valueOf(portStr);
if (port < 0 || port > 65535)
throw new IgniteCheckedException("Invalid port number: " + connStr);
}
catch (NumberFormatException ignored) {
throw new IgniteCheckedException("Invalid port number: " + connStr);
}
}
else
throw new IgniteCheckedException("Invalid connection string format: " + connStr);
return F.t(host, port);
}
/**
* @return IGFS name.
*/
public String igfs() {
return igfsName;
}
/**
* @return Host.
*/
public String host() {
return host;
}
/**
* @return Host.
*/
public boolean isLocal() {
return F.eq(LOCALHOST, host);
}
/**
* @return Port.
*/
public int port() {
return port;
}
/** {@inheritDoc} */
@Override public String toString() {
return S.toString(HadoopIgfsEndpoint.class, this);
}
}