/* * Copyright 2008-2014 the original author or authors * * Licensed 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.kaleidofoundry.core.store; import static org.kaleidofoundry.core.store.FileStoreConstants.HttpStorePluginName; import java.io.FileNotFoundException; import java.io.IOException; import java.net.Authenticator; import java.net.ConnectException; import java.net.InetSocketAddress; import java.net.MalformedURLException; import java.net.PasswordAuthentication; import java.net.Proxy; import java.net.URI; import java.net.URL; import java.net.URLConnection; import org.kaleidofoundry.core.context.RuntimeContext; import org.kaleidofoundry.core.i18n.InternalBundleHelper; import org.kaleidofoundry.core.io.FileHelper; import org.kaleidofoundry.core.io.MimeTypeResolverFactory; import org.kaleidofoundry.core.lang.annotation.NotNull; import org.kaleidofoundry.core.lang.annotation.Task; import org.kaleidofoundry.core.lang.annotation.TaskLabel; import org.kaleidofoundry.core.plugin.Declare; import org.kaleidofoundry.core.util.StringHelper; /** * Http & https {@link FileStore} implementation * <br/> * <br/> * <b>This implementation is only for read only use</b> - the methods store, remove, move will throws {@link ResourceException}<br/> * <br/> * You can create your own store, by extending this class and overriding methods : * <ul> * <li>{@link #doRemove(URI)}</li> * <li>{@link #doStore(URI, ResourceHandler)}</li> * </ul> * Then, annotate {@link Declare} your new class to register your implementation * * @author jraduget * @see FileStoreContextBuilder enum of context configuration properties available */ @Declare(HttpStorePluginName) @Task(labels = TaskLabel.Enhancement, comment = "Create an implementation using commons http client + servlet for store / move / remove methods") public class HttpFileStore extends AbstractFileStore implements FileStore { /** * @param context */ public HttpFileStore(@NotNull final RuntimeContext<FileStore> context) { super(context); } /** * @param baseUri * @param context */ public HttpFileStore(final String baseUri, final RuntimeContext<FileStore> context) { super(baseUri, context); } /** * @see AbstractFileStore#AbstractFileStore() */ HttpFileStore() { super(); } /* * (non-Javadoc) * @see org.kaleidofoundry.core.store.AbstractFileStore#getStoreType() */ @Override public FileStoreType[] getStoreType() { return new FileStoreType[] { FileStoreTypeEnum.http, FileStoreTypeEnum.https }; } /* * (non-Javadoc) * @see org.kaleidofoundry.core.store.AbstractFileStore#isReadOnly() */ @Override public boolean isReadOnly() { return true; } /* * (non-Javadoc) * @see org.kaleidofoundry.core.store.AbstractFileStore#doLoad(java.net.URI) */ @Override protected ResourceHandler doGet(final URI resourceUri) throws ResourceNotFoundException, ResourceException { if (resourceUri.getHost() == null) { throw new IllegalStateException(InternalBundleHelper.StoreMessageBundle.getMessage("store.uri.http.illegal", resourceUri.toString())); } try { /* * # java env. variable to defined proxy globally * # http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/technotes/guides/net/properties.html * http.proxyHost (default: <none>) * http.proxyPort (default: 80 if http.proxyHost specified) * http.nonProxyHosts (default: <none>) */ final URL configUrl = resourceUri.toURL(); final URLConnection urlConnection; Proxy httpProxy = null; // if a proxy is set & active if (!StringHelper.isEmpty(context.getString(FileStoreContextBuilder.ProxySet))) { if (context.getBoolean(FileStoreContextBuilder.ProxySet)) { final String proxyHost = context.getString(FileStoreContextBuilder.ProxyHost); final String proxyPort = context.getString(FileStoreContextBuilder.ProxyPort); if (!StringHelper.isEmpty(proxyHost)) { httpProxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, !StringHelper.isEmpty(proxyPort) ? Integer.parseInt(proxyPort) : 80)); if (!StringHelper.isEmpty(context.getString(FileStoreContextBuilder.NonProxyHosts))) { // :( global... System.getProperties().put("http.nonProxyHosts", context.getProperty(FileStoreContextBuilder.NonProxyHosts)); } if (!StringHelper.isEmpty(context.getString(FileStoreContextBuilder.ProxyUser)) && !StringHelper.isEmpty(context.getString(FileStoreContextBuilder.ProxyPassword))) { // Authenticator is global... :( // other way : urlConnection.setRequestProperty("Proxy-Authorization", Base64.encodeObject(username)); // http://en.wikipedia.org/wiki/Base64 Authenticator.setDefault(new Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(context.getString(FileStoreContextBuilder.ProxyUser), context.getString( FileStoreContextBuilder.ProxyPassword).toCharArray()); } }); } } } } if (httpProxy == null) { // open connection with proxy settings urlConnection = configUrl.openConnection(); } else { // open connection with default proxy settings urlConnection = configUrl.openConnection(httpProxy); } // set commons connection settings setUrlConnectionSettings(urlConnection); // connection urlConnection.connect(); try { ResourceHandler resource = createResourceHandler(resourceUri.toString(), urlConnection.getInputStream()); // Set some meta datas if (resource instanceof ResourceHandlerBean) { ((ResourceHandlerBean) resource).setLastModified(urlConnection.getLastModified()); ((ResourceHandlerBean) resource).setLength(urlConnection.getContentLength()); ((ResourceHandlerBean) resource).setMimeType(MimeTypeResolverFactory.getService().getMimeType( FileHelper.getFileNameExtension(resourceUri.getPath()))); } return resource; } catch (final FileNotFoundException fnfe) { throw new ResourceNotFoundException(resourceUri.toString()); } } catch (final MalformedURLException mure) { throw new IllegalStateException(InternalBundleHelper.StoreMessageBundle.getMessage("store.uri.malformed", resourceUri.toString())); } catch (final ConnectException ce) { throw new ResourceException("store.connection.error", ce, resourceUri.toString()); } catch (final IOException ioe) { if (ioe instanceof ResourceException) { throw (ResourceException) ioe; } else { throw new ResourceException(ioe, resourceUri.toString()); } } } /* * (non-Javadoc) * @see org.kaleidofoundry.core.store.AbstractFileStore#doRemove(java.net.URI) */ @Override protected void doRemove(final URI resourceBinding) throws ResourceNotFoundException, ResourceException { throw new ResourceException("store.readonly.illegal", context.getName()); } /* * (non-Javadoc) * @see org.kaleidofoundry.core.store.AbstractFileStore#doStore(java.net.URI, org.kaleidofoundry.core.store.ResourceHandler) */ @Override protected void doStore(final URI resourceBinding, final ResourceHandler resource) throws ResourceException { throw new ResourceException("store.readonly.illegal", context.getName()); } }