org.eclipse.gyrex.jobs.internal.worker.JobInfo.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.gyrex.jobs.internal.worker.JobInfo.java

Source

/*******************************************************************************
 * Copyright (c) 2011, 2013 AGETO Service GmbH and others.
 * All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html.
 *
 * Contributors:
 *     Gunnar Wagenknecht - initial API and implementation
 *     Mike Tschierschke - improvements due working on https://bugs.eclipse.org/bugs/show_bug.cgi?id=344467
 *******************************************************************************/
package org.eclipse.gyrex.jobs.internal.worker;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream;

import org.eclipse.gyrex.cloud.services.queue.IMessage;
import org.eclipse.gyrex.common.identifiers.IdHelper;

import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;

import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;

/**
 * Serialization/deserialization helper for Job queue messages.
 */
public class JobInfo {

    private static final String PREFIX = "gyrex.jobinfo."; //$NON-NLS-1$
    private static final String ID = PREFIX + "jobid"; //$NON-NLS-1$
    private static final String TYPE_ID = PREFIX + "jobtype"; //$NON-NLS-1$
    private static final String CONTEXT_PATH = PREFIX + "jobcontext"; //$NON-NLS-1$
    private static final String QUEUE_TRIGGER = PREFIX + "queueTrigger"; //$NON-NLS-1$
    private static final String QUEUE_TIMESTAMP = PREFIX + "queueTimestamp"; //$NON-NLS-1$
    private static final String VERSION = PREFIX + "version"; //$NON-NLS-1$
    private static final String VERSION_VALUE = "1"; //$NON-NLS-1$
    private static final String SCHEDULE_INFO = PREFIX + "scheduleInfo"; //$NON-NLS-1$
    private static final String LAST_SUCCESSFUL_START = PREFIX + "lastSuccessfulStart"; //$NON-NLS-1$

    public static byte[] asMessage(final JobInfo info) throws IOException {
        final Properties properties = new Properties();

        // collect properties
        final Map<String, String> jobProperties = info.getJobProperties();
        for (final Entry<String, String> entry : jobProperties.entrySet()) {
            properties.put(entry.getKey(), entry.getValue());
        }

        // put properties
        try {
            properties.put(VERSION, VERSION_VALUE);
            properties.put(ID, info.getJobId());
            properties.put(TYPE_ID, info.getJobTypeId());
            properties.put(CONTEXT_PATH, info.getContextPath().toString());
            properties.put(QUEUE_TRIGGER, info.getQueueTrigger());
            properties.put(QUEUE_TIMESTAMP, String.valueOf(info.getQueueTimestamp()));
            properties.put(LAST_SUCCESSFUL_START, String.valueOf(info.getLastSuccessfulStart()));
            if (StringUtils.isNotBlank(info.getScheduleInfo())) {
                properties.put(SCHEDULE_INFO, info.getScheduleInfo());
            }
        } catch (final NullPointerException e) {
            // we tried to put null into the properties map
            throw new IllegalArgumentException(String.format("Invalid job info: %s", info));
        }

        // create bytes
        final ByteArrayOutputStream out = new ByteArrayOutputStream();
        try (final DeflaterOutputStream df = new DeflaterOutputStream(out)) {
            properties.store(df, null);
        }
        return out.toByteArray();
    }

    public static JobInfo parse(final IMessage message) throws IOException {
        final Properties properties = new Properties();
        try (InflaterInputStream in = new InflaterInputStream(new ByteArrayInputStream(message.getBody()))) {
            properties.load(in);
        }

        // check version (remove key from properties)
        final Object versionValue = properties.remove(VERSION);
        if (!VERSION_VALUE.equals(versionValue))
            throw new IOException(String.format("invalid record data: version mismatch (expected %s, found %s)",
                    VERSION_VALUE, String.valueOf(versionValue)));

        // get id (remove key from properties as well)
        final Object jobIdValue = properties.remove(ID);
        if ((null == jobIdValue) || !(jobIdValue instanceof String) || !IdHelper.isValidId(((String) jobIdValue)))
            throw new IOException(
                    String.format("invalid record data: missing/invalid job id %s", String.valueOf(jobIdValue)));

        // get type (remove key from properties as well)
        final Object jobTypeValue = properties.remove(TYPE_ID);
        if ((null == jobTypeValue) || !(jobTypeValue instanceof String)
                || !IdHelper.isValidId(((String) jobTypeValue)))
            throw new IOException(
                    String.format("invalid record data: missing/invalid job id %s", String.valueOf(jobTypeValue)));

        // get path (remove key from properties as well)
        final Object contextPathValue = properties.remove(CONTEXT_PATH);
        if ((null == contextPathValue) || !(contextPathValue instanceof String)
                || !Path.EMPTY.isValidPath(((String) contextPathValue)))
            throw new IOException(String.format("invalid record data: missing/invalid context path %s",
                    String.valueOf(contextPathValue)));

        // get queue trigger (remove key from properties as well)
        final Object queueTrigger = properties.remove(QUEUE_TRIGGER);
        if ((null != queueTrigger) && !(queueTrigger instanceof String))
            throw new IOException(
                    String.format("invalid record data: invalid queue trigger %s", String.valueOf(queueTrigger)));

        // get queue timestamp (remove key from properties as well)
        final Object queueTimestamp = properties.remove(QUEUE_TIMESTAMP);
        if ((null == queueTimestamp) || !(queueTimestamp instanceof String))
            throw new IOException(String.format("invalid record data: missing/invalid queue timestamp %s",
                    String.valueOf(queueTimestamp)));

        // get schedule info (remove key from properties as well)
        final Object scheduleInfo = properties.remove(SCHEDULE_INFO);
        if ((null != scheduleInfo) && !(scheduleInfo instanceof String))
            throw new IOException(
                    String.format("invalid record data: invalid schedule info %s", String.valueOf(scheduleInfo)));

        // get last successful finish timestamp (remove key from properties as well)
        final Object lastSuccessfulStart = properties.remove(LAST_SUCCESSFUL_START);
        if ((null == lastSuccessfulStart) || !(lastSuccessfulStart instanceof String))
            throw new IOException(
                    String.format("invalid record data: missing/invalid last successful finish timestamp %s",
                            String.valueOf(lastSuccessfulStart)));

        // collect properties
        final Map<String, String> jobProperties = new HashMap<String, String>();
        for (final Iterator<?> stream = properties.keySet().iterator(); stream.hasNext();) {
            final String key = (String) stream.next();
            if (!key.startsWith(PREFIX)) {
                jobProperties.put(key, properties.getProperty(key));
            }
        }

        // create job info
        return new JobInfo((String) jobTypeValue, (String) jobIdValue, new Path((String) contextPathValue),
                jobProperties, (String) queueTrigger, NumberUtils.toLong((String) queueTimestamp),
                (String) scheduleInfo, NumberUtils.toLong((String) lastSuccessfulStart));
    }

    private final String jobId;

    private final String jobTypeId;
    private final Map<String, String> jobProperties;
    private final IPath contextPath;
    private final String queueTrigger;
    private final long queueTimestamp;
    private final String scheduleInfo;
    private final long lastSuccessfulStart;

    public JobInfo(final String jobTypeId, final String jobId, final IPath contextPath,
            final Map<String, String> jobProperties, final String queueTrigger, final long queueTimestamp,
            final String scheduleInfo, final long lastSuccessfulStart) {
        this.jobId = jobId;
        this.jobTypeId = jobTypeId;
        this.contextPath = contextPath;
        this.jobProperties = jobProperties;
        this.queueTrigger = queueTrigger;
        this.queueTimestamp = queueTimestamp;
        this.scheduleInfo = scheduleInfo;
        this.lastSuccessfulStart = lastSuccessfulStart;
    }

    public IPath getContextPath() {
        return contextPath;
    }

    public String getJobId() {
        return jobId;
    }

    public Map<String, String> getJobProperties() {
        return jobProperties;
    }

    public String getJobTypeId() {
        return jobTypeId;
    }

    public long getLastSuccessfulStart() {
        return lastSuccessfulStart;
    }

    public long getQueueTimestamp() {
        return queueTimestamp;
    }

    public String getQueueTrigger() {
        return queueTrigger;
    }

    public String getScheduleInfo() {
        return scheduleInfo;
    }

    @Override
    public String toString() {
        final StringBuilder builder = new StringBuilder();
        builder.append("JobInfo [jobId=").append(jobId).append(", jobTypeId=").append(jobTypeId)
                .append(", contextPath=").append(contextPath).append(", queueTrigger=").append(queueTrigger)
                .append(", queueTimestamp=").append(queueTimestamp).append(", scheduleInfo=").append(scheduleInfo)
                .append(", lastSuccessfulStart=").append(lastSuccessfulStart).append(", jobProperties=")
                .append(jobProperties).append("]");
        return builder.toString();
    }
}