/* * 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); } }