org.hashes.CollisionInjector.java Source code

Java tutorial

Introduction

Here is the source code for org.hashes.CollisionInjector.java

Source

/**
 *    Copyright 2012 Pedro Ribeiro
 *
 *    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.hashes;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hashes.config.Configuration;
import org.hashes.config.HttpHost;
import org.hashes.config.Protocol;
import org.hashes.progress.ProgressMonitorFactory;
import org.hashes.util.FileUtils;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import com.google.common.net.HttpHeaders;

/**
 * Collision injector.
 * 
 * @author ribeirux
 * @version $Revision$
 */
public class CollisionInjector {

    private static final Log LOG = LogFactory.getLog(CollisionInjector.class);

    private final Configuration configuration;

    /**
     * Creates a new instance with specified configuration.
     * 
     * @param configuration the configuration
     */
    public CollisionInjector(final Configuration configuration) {
        this.configuration = Preconditions.checkNotNull(configuration, "configuration");
    }

    /**
     * Gets the configuration property.
     * 
     * @return the configuration property
     */
    public Configuration getConfiguration() {
        return this.configuration;
    }

    /**
     * Starts injecting collisions.
     */
    public void start() {

        final ProgressMonitorFactory factory = this.configuration.getProgressMonitorFactory();
        final int numberOfKeys = this.configuration.getNumberOfKeys();
        final boolean newKeys = this.configuration.isGenerateNewKeys();

        final List<String> collisions = this.configuration.getCollisionGenerator().generateCollisions(numberOfKeys,
                factory, newKeys);

        this.saveCollisions(collisions);

        final byte[] payload = this.buildPayload(collisions);

        final int numberOfClients = this.configuration.getNumberOfClients();
        final Builder<Runnable> clients = ImmutableList.builder();

        for (int i = 0; i < numberOfClients; i++) {
            clients.add(this.createClient(payload));
        }

        this.runClients(clients.build());
    }

    protected void saveCollisions(final List<String> collisions) {

        final File toSave = this.configuration.getCollisionsFile();
        if (toSave != null) {
            if (LOG.isInfoEnabled()) {
                LOG.info("Saving collisions to file: " + toSave.getPath());
            }

            try {
                FileUtils.writeLines(toSave, collisions, this.configuration.getCharset());
            } catch (final IOException e) {
                if (LOG.isErrorEnabled()) {
                    LOG.error("Could not save collisions to file: " + toSave.getAbsolutePath(), e);
                }
            }
        }
    }

    protected byte[] buildPayload(final List<String> collisions) {

        final String body = this.buildMessageBody(collisions);

        final StringBuilder payloadBuilder = new StringBuilder();
        this.addRequestLine(payloadBuilder);
        this.addRequestHeaders(body.length(), payloadBuilder);

        payloadBuilder.append(body);

        return payloadBuilder.toString().getBytes(this.configuration.getCharset());
    }

    protected void addRequestLine(final StringBuilder payloadBuilder) {

        payloadBuilder.append("POST ");
        payloadBuilder.append(this.configuration.getPath());
        payloadBuilder.append(" HTTP/1.1\r\n");
    }

    protected void addRequestHeaders(final int contentLength, final StringBuilder payloadBuilder) {

        // http://www.ietf.org/rfc/rfc2616.txt
        // Each header field consists of a name followed by a colon (":") and the field value. Field names are
        // case-insensitive.
        final Locale locale = Locale.ENGLISH;
        final Map<String, String> defaultHeaders = new LinkedHashMap<String, String>();
        defaultHeaders.put(HttpHeaders.HOST.toLowerCase(locale), this.configuration.getTarget().getHost());
        defaultHeaders.put(HttpHeaders.CONTENT_TYPE.toLowerCase(locale), "application/x-www-form-urlencoded");
        defaultHeaders.put(HttpHeaders.ACCEPT_CHARSET.toLowerCase(locale), this.configuration.getCharset().name());
        defaultHeaders.put(HttpHeaders.CONTENT_LENGTH.toLowerCase(locale), String.valueOf(contentLength));
        defaultHeaders.put(HttpHeaders.USER_AGENT.toLowerCase(locale), "hashes");
        defaultHeaders.put(HttpHeaders.ACCEPT.toLowerCase(locale), "*/*");

        for (final Entry<String, String> externalHeaders : this.configuration.getHeaders().entrySet()) {
            defaultHeaders.put(externalHeaders.getKey().toLowerCase(locale), externalHeaders.getValue());
        }

        for (final Entry<String, String> header : defaultHeaders.entrySet()) {
            payloadBuilder.append(header.getKey());
            payloadBuilder.append(": ");
            payloadBuilder.append(header.getValue());
            payloadBuilder.append("\r\n");
        }

        payloadBuilder.append("\r\n");
    }

    protected String buildMessageBody(final List<String> collisions) {

        final StringBuilder payloadBuilder = new StringBuilder();

        final String charsetName = this.configuration.getCharset().name();

        final Iterator<String> iterator = collisions.iterator();

        try {
            if (iterator.hasNext()) {
                payloadBuilder.append(URLEncoder.encode(iterator.next(), charsetName));
                payloadBuilder.append("=");
            }

            while (iterator.hasNext()) {
                payloadBuilder.append("&");
                payloadBuilder.append(URLEncoder.encode(iterator.next(), charsetName));
                payloadBuilder.append("=");
            }
        } catch (final UnsupportedEncodingException e) {
            throw new UnsupportedPayloadEncodingException(e);
        }

        return payloadBuilder.toString();
    }

    protected Runnable createClient(final byte[] payload) {
        final HttpHost target = this.configuration.getTarget();

        Runnable client;
        if (target.getProtocol() == Protocol.HTTP) {
            client = new HttpClient(//
                    this.configuration.getRequestsPerClient(), //
                    target, //
                    payload, //
                    this.configuration.isWaitResponse(), //
                    this.configuration.getCharset());
        } else if (target.getProtocol() == Protocol.HTTPS) {
            client = new HttpsClient(//
                    this.configuration.getRequestsPerClient(), //
                    target, //
                    payload, //
                    this.configuration.isWaitResponse(), //
                    this.configuration.getCharset());
        } else {
            throw new UnsupportedOperationException("Client not implemented for protocol: " + target.getProtocol());
        }

        return client;
    }

    /**
     * Run the specified clients on each thread.
     * 
     * @param clients clients to run
     */
    protected void runClients(final List<Runnable> clients) {
        Preconditions.checkNotNull(clients, "clients");

        final int numberOfClients = clients.size();

        if (LOG.isInfoEnabled()) {
            LOG.info("Starting " + clients.size() + " client(s)");
        }

        final ExecutorService executor = Executors.newFixedThreadPool(numberOfClients);
        try {
            for (final Runnable client : clients) {
                executor.execute(client);
            }
        } finally {
            executor.shutdown();
        }
    }
}