Java tutorial
/* * 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 com.datos.vfs.provider.http; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import com.datos.vfs.FileContentInfoFactory; import com.datos.vfs.FileSystemException; import com.datos.vfs.FileSystemOptions; import com.datos.vfs.provider.AbstractFileObject; import com.datos.vfs.provider.URLFileName; import com.datos.vfs.util.MonitorInputStream; import com.datos.vfs.util.RandomAccessMode; import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpMethod; import org.apache.commons.httpclient.URIException; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.methods.HeadMethod; import org.apache.commons.httpclient.util.DateUtil; import org.apache.commons.httpclient.util.URIUtil; import com.datos.vfs.FileNotFoundException; import com.datos.vfs.FileType; import com.datos.vfs.RandomAccessContent; import com.datos.vfs.provider.AbstractFileName; /** * A file object backed by Apache Commons HttpClient. * <p> * TODO - status codes. * * @param <FS> An {@link HttpFileSystem} subclass */ public class HttpFileObject<FS extends HttpFileSystem> extends AbstractFileObject<FS> { /** * An InputStream that cleans up the HTTP connection on close. */ static class HttpInputStream extends MonitorInputStream { private final GetMethod method; public HttpInputStream(final GetMethod method) throws IOException { super(method.getResponseBodyAsStream()); this.method = method; } /** * Called after the stream has been closed. */ @Override protected void onClose() throws IOException { method.releaseConnection(); } } private final String urlCharset; private final String userAgent; private final boolean followRedirect; private HeadMethod method; protected HttpFileObject(final AbstractFileName name, final FS fileSystem) { this(name, fileSystem, HttpFileSystemConfigBuilder.getInstance()); } protected HttpFileObject(final AbstractFileName name, final FS fileSystem, final HttpFileSystemConfigBuilder builder) { super(name, fileSystem); final FileSystemOptions fileSystemOptions = fileSystem.getFileSystemOptions(); urlCharset = builder.getUrlCharset(fileSystemOptions); userAgent = builder.getUserAgent(fileSystemOptions); followRedirect = builder.getFollowRedirect(fileSystemOptions); } /** * Detaches this file object from its file resource. */ @Override protected void doDetach() throws Exception { method = null; } /** * Returns the size of the file content (in bytes). */ @Override protected long doGetContentSize() throws Exception { final Header header = method.getResponseHeader("content-length"); if (header == null) { // Assume 0 content-length return 0; } return Long.parseLong(header.getValue()); } /** * Creates an input stream to read the file content from. Is only called * if {@link #doGetType} returns {@link FileType#FILE}. * <p> * It is guaranteed that there are no open output streams for this file * when this method is called. * <p> * The returned stream does not have to be buffered. */ @Override protected InputStream doGetInputStream() throws Exception { final GetMethod getMethod = new GetMethod(); setupMethod(getMethod); final int status = getAbstractFileSystem().getClient().executeMethod(getMethod); if (status == HttpURLConnection.HTTP_NOT_FOUND) { throw new FileNotFoundException(getName()); } if (status != HttpURLConnection.HTTP_OK) { throw new FileSystemException("vfs.provider.http/get.error", getName(), Integer.valueOf(status)); } return new HttpInputStream(getMethod); } /** * Returns the last modified time of this file. * <p> * This implementation throws an exception. */ @Override protected long doGetLastModifiedTime() throws Exception { final Header header = method.getResponseHeader("last-modified"); if (header == null) { throw new FileSystemException("vfs.provider.http/last-modified.error", getName()); } return DateUtil.parseDate(header.getValue()).getTime(); } @Override protected RandomAccessContent doGetRandomAccessContent(final RandomAccessMode mode) throws Exception { return new HttpRandomAccessContent(this, mode); } /** * Determines the type of this file. Must not return null. The return * value of this method is cached, so the implementation can be expensive. */ @Override protected FileType doGetType() throws Exception { // Use the HEAD method to probe the file. final int status = this.getHeadMethod().getStatusCode(); if (status == HttpURLConnection.HTTP_OK || status == HttpURLConnection.HTTP_BAD_METHOD /* method is bad, but resource exist */) { return FileType.FILE; } else if (status == HttpURLConnection.HTTP_NOT_FOUND || status == HttpURLConnection.HTTP_GONE) { return FileType.IMAGINARY; } else { throw new FileSystemException("vfs.provider.http/head.error", getName(), Integer.valueOf(status)); } } @Override protected boolean doIsWriteable() throws Exception { return false; } /** * Lists the children of this file. */ @Override protected String[] doListChildren() throws Exception { throw new Exception("Not implemented."); } protected String encodePath(final String decodedPath) throws URIException { return URIUtil.encodePath(decodedPath); } @Override protected FileContentInfoFactory getFileContentInfoFactory() { return new HttpFileContentInfoFactory(); } protected boolean getFollowRedirect() { return followRedirect; } protected String getUserAgent() { return userAgent; } HeadMethod getHeadMethod() throws IOException { if (method != null) { return method; } method = new HeadMethod(); setupMethod(method); final HttpClient client = getAbstractFileSystem().getClient(); client.executeMethod(method); method.releaseConnection(); return method; } protected String getUrlCharset() { return urlCharset; } /** * Prepares a HttpMethod object. * * @param method The object which gets prepared to access the file object. * @throws FileSystemException if an error occurs. * @throws URIException if path cannot be represented. * @since 2.0 (was package) */ protected void setupMethod(final HttpMethod method) throws FileSystemException, URIException { final String pathEncoded = ((URLFileName) getName()).getPathQueryEncoded(this.getUrlCharset()); method.setPath(pathEncoded); method.setFollowRedirects(this.getFollowRedirect()); method.setRequestHeader("User-Agent", this.getUserAgent()); } /* protected Map doGetAttributes() throws Exception { TreeMap map = new TreeMap(); Header contentType = method.getResponseHeader("content-type"); if (contentType != null) { HeaderElement[] element = contentType.getValues(); if (element != null && element.length > 0) { map.put("content-type", element[0].getName()); } } map.put("content-encoding", method.getResponseCharSet()); return map; } */ }