HTTPChunkLocator.java Source code

Java tutorial

Introduction

Here is the source code for HTTPChunkLocator.java

Source

/**
 * 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.
 */

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;

import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;

/**
 * The HTTPChunkLocator class implements the REST API access for determining
 * chunk locations.
 */

public class HTTPChunkLocator extends ChunkLocator {

    private static final String CHUNK_ID = "chunk";
    private static final String COPY_ID = "copy";
    private static final QName Q_IP_ADDR = new QName("ip_addr");
    private static final QName Q_NAME = new QName("name");
    private static final QName Q_VID = new QName("vid");
    private static final QName Q_CHUNK_SIZE = new QName("chunk_size");
    private static final QName Q_OFFSET = new QName("offset");

    @Override
    public void release() throws ChunkStorageException {

    }

    @Override
    public ChunkLocation[] getChunkLocations(final File file, final String virtualFsName)
            throws ChunkStorageException {
        final long inode = getInode(file);
        final long fileSizeInBytes = getFileSizeInBytes(file);

        final XMLInputFactory factory = XMLInputFactory.newInstance();
        XMLEventReader reader = null;
        try {
            final URI uri = new URI(endpoint.getScheme(), endpoint.getUserInfo(), endpoint.getHost(),
                    endpoint.getPort(), endpoint.getPath(), "inum=" + inode, null);
            reader = factory.createXMLEventReader(openStream(uri));
            final List<ChunkLocation> parseChunks = parseChunks(reader, fileSizeInBytes);
            return parseChunks.toArray(new ChunkLocation[0]);
        } catch (final Exception e) {
            throw new ChunkStorageException(e);
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (final XMLStreamException e) {
                    // ignore
                }
            }
        }
    }

    private final HttpClient client;
    private final URI endpoint;
    public static final String DEFAULT_PATH = "mproxy/map_obj";

    public HTTPChunkLocator(final HttpClient client, URI aUri) {
        final HttpConnectionManagerParams params = client.getHttpConnectionManager().getParams();
        params.setConnectionTimeout(10000);
        params.setTcpNoDelay(true);
        params.setDefaultMaxConnectionsPerHost(10);
        client.getHttpConnectionManager().setParams(params);
        this.client = client;
        this.endpoint = aUri;

    }

    private InputStream openStream(final URI aUri) throws IOException {
        final GetMethod method = new GetMethod(aUri.toString());
        method.setFollowRedirects(true);
        client.executeMethod(method);
        final int statusCode = method.getStatusCode();
        if (statusCode != 200) {
            method.abort();
            throw new IOException(String.format("HTTP Status Code %s for URL %s", statusCode, aUri));
        }
        return method.getResponseBodyAsStream();
    }

    /**
     * parses a chunk info part
     * <p/>
     * <pre>
     *  <chunk_list>
     *    <chunk offset="0" chunk_size="67108864">
     *      <map>
     *        <copy ip_addr="10.10.2.200" name="vistasn1" snid="1" vid="1" />
     *        <copy ip_addr="10.10.2.201" name="vistasn2" snid="2" vid="3" />
     *     </map>
     *    </chunk>
     *  </chunk_list>
     * </pre>
     */
    private List<ChunkLocation> parseChunks(final XMLEventReader reader, final long fileSizeInBytes)
            throws XMLStreamException, IOException {
        long offset = -1;
        long length = -1;
        final List<ChunkLocation> locations = new ArrayList<ChunkLocation>(5);
        final List<StorageNodeInfo> sninfo = new ArrayList<StorageNodeInfo>();
        final List<Integer> volumeIds = new ArrayList<Integer>();
        while (reader.hasNext()) {
            final XMLEvent nextEvent = reader.nextEvent();
            if (!(nextEvent instanceof StartElement)) {
                continue;
            }
            final StartElement start = (StartElement) nextEvent;
            if (CHUNK_ID.equals(start.getName().getLocalPart())) {
                if (sninfo.size() > 0) {
                    final ChunkInfo chunkInfo = new ChunkInfo(offset, length, volumeIds.toArray(new Integer[0]));
                    locations.add(
                            new ChunkLocation(sninfo.toArray(new StorageNodeInfo[0]), chunkInfo, fileSizeInBytes));
                    sninfo.clear();
                    volumeIds.clear();
                }
                offset = Long.parseLong(get(start, Q_OFFSET));
                length = Long.parseLong(get(start, Q_CHUNK_SIZE));

            } else if (COPY_ID.equals(start.getName().getLocalPart())) {
                final InetAddress ip = InetAddress.getByName(get(start, Q_IP_ADDR));
                final int vid = Integer.parseInt(get(start, Q_VID));
                final String name = get(start, Q_NAME);
                sninfo.add(new StorageNodeInfo(name, ip.getHostAddress(), true, true));
                volumeIds.add(Integer.valueOf(vid));

            }
        }
        if (sninfo.size() > 0) {
            final ChunkInfo chunkInfo = new ChunkInfo(offset, length, volumeIds.toArray(new Integer[0]));
            locations.add(new ChunkLocation(sninfo.toArray(new StorageNodeInfo[0]), chunkInfo, fileSizeInBytes));
        }
        return locations;
    }

    private static String get(final StartElement element, final QName name) throws IOException {
        final Attribute attributeByName = element.getAttributeByName(name);
        if (attributeByName == null) {
            throw new IOException("missing attribute " + name.toString());
        }
        return attributeByName.getValue();
    }

    @Override
    public String toString() {
        return "HTTPChunkLocator [endpoint=" + endpoint + "]";
    }

}