All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.day.cq.polling.importer.HCImporter Maven / Gradle / Ivy

/*************************************************************************
 *
 * ADOBE CONFIDENTIAL
 * ___________________
 *
 *  Copyright 2014 Adobe Systems Incorporated
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Adobe Systems Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Adobe Systems Incorporated and its
 * suppliers and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Adobe Systems Incorporated.
 **************************************************************************/

package com.day.cq.polling.importer;

import java.io.IOException;
import java.io.InputStream;

import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.HttpClientUtils;
import org.apache.http.entity.ContentType;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.sling.api.resource.Resource;
import org.osgi.service.component.ComponentContext;

import aQute.bnd.annotation.ConsumerType;


/**
 * The HCImporter is an abstract implementation of the
 * {@link Importer} service interface supporting access to data using the HTTP
 * protocol.
 * 

* Extensions of this base class must implement the * {@link #importData(String, InputStream, String, Resource)} method to actually * import the retrieved data. *

* Instances of this base class must be initialized before being used and * be destroyed when not used any more. If the extension is registered as an * Declarative Services Component, this initialization and destroyal is being * taken care of. Otherwise, the extension class must explicitly call the * {@link #init()} and {@link #destroy()} methods respectively. *

* The {@link #activate(ComponentContext)} and * {@link #deactivate(ComponentContext)} methods may be overwritten by extension * classes but the base class implementation must called in this case to * ensure proper initialization and destroyal. */ @Component(metatype = false, componentAbstract = true) @Service(Importer.class) @Properties({ @Property(name = "service.description", value = "Abstract HTTP based Importer") }) @ConsumerType public abstract class HCImporter implements Importer { /** * The HTTP Client used by this importer instance. This field is initialized * on demand by the {@link #getHttpClient()} method and cleared by the * {@link #destroy()} method. */ private HttpClient httpClient; /** * Actually imports the data received from the data source into the target * Resource. *

* Implementations of this method need not (and should not) close the * data input stream. This will be taken care of the caller of * this method. * * @param scheme The scheme describing the data to import. * @param data The data to be imported. * @param characterEncoding If the data contains character data, such as * XML, this parameter (may) provide the character encoding of * the character data. The value of this parameter is extracted * from the Content-Type header of the HTTP response * and may thus be empty or null if not set by the * server. * @param target The Resource into which the data is to be * imported. * @throws IOException May be thrown if an error occurs reading or writing * the imported data. * @throws ImportException May be thrown in any other error case. */ protected abstract void importData(String scheme, InputStream data, String characterEncoding, Resource target) throws IOException; // ---------- Importer interface /** * Imports data from the given source which is expected to be * an HTTP URL. This method uses the Apache Http Client library to * request the source with a method provided by {@link #newHttpMethod(String)} the * response stream is then provided to the * {@link #importData(String, InputStream, String, Resource)} method, which * must be implemented by the extension. * * @param scheme The scheme of the data source. This parameter is handed * over to the * {@link #importData(String, InputStream, String, Resource)} * method. * @param dataSource The HTTP URL to the data to be imported. * @param target The Resource into which the data is to be * imported. * @throws ImportException If an error occurs while accessing the source or * if this class has not been initialized or if an error occurs * while importing the actual data through * {@link #importData(String, InputStream, String, Resource)}. */ public void importData(String scheme, String dataSource, Resource target) { importData(scheme, dataSource, target, null, null); } /** * Imports data from the given source which is expected to be * an HTTP URL. This method uses the Apache Http Client library to * request the source with a method provided by {@link #newHttpMethod(String)} the * response stream is then provided to the * {@link #importData(String, InputStream, String, Resource)} method, which * must be implemented by the extension. * * @param scheme The scheme of the data source. This parameter is handed * over to the * {@link #importData(String, InputStream, String, Resource)} * method. * @param dataSource The HTTP URL to the data to be imported. * @param target The Resource into which the data is to be * imported. * @param login The login to authenticate the request. * @param password The password to authenticate the request. * @throws ImportException If an error occurs while accessing the source or * if this class has not been initialized or if an error occurs * while importing the actual data through * {@link #importData(String, InputStream, String, Resource)}. */ public void importData(String scheme, String dataSource, Resource target, String login, String password) { // the method to execute HttpRequestBase method = newHttpMethod(dataSource); InputStream ins = null; try { // if login information is present, setup the authentication on the httpclient if (login != null && login.length() > 0 && password != null && password.length() > 0) { CredentialsProvider credsProvider = new BasicCredentialsProvider(); Credentials defaultcreds = new UsernamePasswordCredentials(login, password); credsProvider.setCredentials(AuthScope.ANY, defaultcreds); httpClient = HttpClientBuilder.create().setDefaultCredentialsProvider(credsProvider).build(); } // execute the request and check the status HttpResponse httpResp = getHttpClient().execute(method); if(httpResp != null) { int statusCode = httpResp.getStatusLine().getStatusCode(); switch (statusCode) { case HttpStatus.SC_OK: // this what we expect break; case HttpStatus.SC_NOT_MODIFIED: // no change in data, so just get back out of here return; default: // this is what we don't expect throw new ImportException("Failed retreiving data" + httpResp.getStatusLine()); } } // access the raw response stream and import it if(httpResp.getEntity() != null) { ins = httpResp.getEntity().getContent(); } String charset = null; if(null != ContentType.getOrDefault(httpResp.getEntity()).getCharset()) { charset = ContentType.getOrDefault(httpResp.getEntity()).getCharset().toString(); } importData(scheme, ins, charset, target); } catch (IOException e) { throw new ImportException("Fatal transport error", e); } catch (IllegalStateException ise) { throw new ImportException( "HttpImporter has not been initialized yet", ise); } catch (Exception e) { throw new ImportException( "Unexpected problem while importing data", e); } finally { // close the response input stream if (ins != null) { try { ins.close(); } catch (IOException ioe) { } } // Release the connection. method.releaseConnection(); } } /** * Returns a HttpClient instance used by the * {@link #importData(String, InputStream, String, Resource)} method to * access the data source URL. The HttpClient instance is * backed by a PoolingHttpClientConnectionManager. *

* This method cannot be overwritten. To configure the HttpClient, the * {@link #init()} method should be called with appropriate parameters which * are used to setup the client with an instance of the * HttpClientParams class. * * @return the HttpClient instance. * @see #init() */ protected final HttpClient getHttpClient() { PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(); if (httpClient == null) { httpClient = HttpClients.custom() .setConnectionManager(cm) .build(); } return httpClient; } /** * Returns a HttpRequestBase instance used by the * {@link #importData(String, String, Resource)} method to actually retrieve * the data to be imported from the data source URL. *

* This base class implementation returns a plain HttpGet. * Extensions may overwrite to implement more sophisticated method setup. *

* Each call to this method must return a new instance of the * HttpRequestBase implementation. The * {@link #importData(String, String, Resource)} method using this instance * takes care to release the connection of the method when being done. * * @param source The data source URL for which to prepare the method * instance. * @return The HttpRequestBase to import the data, which is in * this base class implementation a HttpGet instance. */ protected HttpRequestBase newHttpMethod(String source) { return new HttpGet(source); } /** * Initializes this base class implementation. This method must be * called before the {@link #importData(String, String, Resource)} may be * used. *

* If the class is used as a Declarative Services component, this method * need not be called explicitly, since the * {@link #activate(ComponentContext)} method will call it. *

* This method may be called multiple times. After a first initialization * further successive calls without {@link #destroy() destroyal} will have * no effect. */ protected final void init() { // nothing at the moment, might set configuration } /** * Destroys this base class implementation. This method must be * called when the instance is not used any more. *

* If the class is used as a Declarative Services component, this method * need not be called explicitly, since the * {@link #deactivate(ComponentContext)} method will call it. *

* This method may be called multiple times. After a first destroyal further * successive calls without {@link #init() initialization} will have no * effect. */ protected final void destroy() { if (httpClient != null) { HttpClientUtils.closeQuietly(httpClient); } httpClient = null; } // ---------- SCR integration /** * This base class implementation currently just calls the {@link #init()} * method. Nevertheless it must be called if overwritten! * * @param context Component context */ protected void activate(ComponentContext context) { init(); } /** * This base class implementation currently just calls the * {@link #destroy()} method. Nevertheless it must be called if * overwritten! * * @param context Component context */ protected void deactivate(ComponentContext context) { destroy(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy