io.github.data4all.util.upload.ChangesetUtil.java Source code

Java tutorial

Introduction

Here is the source code for io.github.data4all.util.upload.ChangesetUtil.java

Source

/*
 * Copyright (c) 2014, 2015 Data4All
 * 
 * <p>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
 * 
 * <p>http://www.apache.org/licenses/LICENSE-2.0
 * 
 * <p>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 io.github.data4all.util.upload;

import io.github.data4all.handler.DataBaseHandler;
import io.github.data4all.model.data.DataElement;
import io.github.data4all.model.data.User;
import io.github.data4all.util.OsmChangeParser;
import io.github.data4all.util.oauth.exception.OsmException;
import io.github.data4all.util.oauth.parameters.OAuthParameters;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import oauth.signpost.OAuthConsumer;
import oauth.signpost.commonshttp.CommonsHttpOAuthConsumer;
import oauth.signpost.exception.OAuthCommunicationException;
import oauth.signpost.exception.OAuthExpectationFailedException;
import oauth.signpost.exception.OAuthMessageSignerException;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.StringEntity;
import org.apache.http.params.BasicHttpParams;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.ResultReceiver;

/**
 * This class provides several methods for creating, parsing and uploading
 * changssets.
 * 
 * @author Richard (first implementations, + added the closeChangeset)
 * @author tbrose (sourcecode rearrangement)
 *
 */
@SuppressLint("SimpleDateFormat")
public final class ChangesetUtil {

    /**
     * Private Constructor, prevents instantiation.
     */
    private ChangesetUtil() {
    }

    /**
     * Returns a Changeset-Request to send to the OSM API.
     * 
     * @param comment
     *            The Comment specified for by the User.
     * @return The Changeset-Request.
     */
    private static String getChangesetRequest(String comment) {
        return "<osm>\n<changeset>\n" + "<tag k=\"created_by\" v=\"Data4All\"/>\n" + "<tag k=\"comment\" v=\""
                + comment + "\"/>\n" + "</changeset>\n</osm>";
    }

    /**
     * Creates a {@link HttpPut} request and signs it by writing an OAuth
     * signature to it.
     * 
     * @param user
     *            The {@link User} account to sign the {@link HttpPut} with.
     * @return A {@link HttpPut} Request.
     * @throws OsmException
     *             Indicates an failure in an osm progess.
     */
    private static HttpPut getChangeSetPut(User user) throws OsmException {
        final OAuthParameters params = OAuthParameters.CURRENT;
        final OAuthConsumer consumer = new CommonsHttpOAuthConsumer(params.getConsumerKey(),
                params.getConsumerSecret());
        consumer.setTokenWithSecret(user.getOAuthToken(), user.getOauthTokenSecret());
        final HttpPut httpPut = new HttpPut(params.getScopeUrl() + "api/0.6/changeset/create");
        try {
            consumer.sign(httpPut);
        } catch (OAuthMessageSignerException e) {
            throw new OsmException(e);
        } catch (OAuthExpectationFailedException e) {
            throw new OsmException(e);
        } catch (OAuthCommunicationException e) {
            throw new OsmException(e);
        }
        return httpPut;
    }

    /**
     * Requests a changeset-id from the OSM-API.
     * 
     * @param user
     *            The {@link User} to request a id for.
     * @param comment
     *            The Comment for the Changeset.
     * @return The Changeset ID.
     * @throws OsmException
     *             If the Changeset ID cannot be grabbed.
     */
    public static CloseableRequest requestId(final User user, final String comment) throws OsmException {
        try {
            final HttpPut request = getChangeSetPut(user);
            // Add the xml-request-string
            request.setEntity(new StringEntity(getChangesetRequest(comment)));

            return new CloseableRequest(request);

        } catch (UnsupportedEncodingException e) {
            throw new OsmException(e);
        }
    }

    /**
     * Parses all objects from the database into an xml structure to create a
     * new Changeset.
     * 
     * @param context
     *            The application context for the {@link DataBaseHandler}.
     * @param changesetId
     *            The Changeset ID from the OSM API.
     * @return The created Changeset.
     * @throws OsmException
     *             Indicates an failure in an osm progess.
     */
    public static String getChangesetXml(Context context, int changesetId) throws OsmException {
        final DataBaseHandler db = new DataBaseHandler(context);
        final List<DataElement> elems = db.getAllDataElements();
        db.close();

        final StringBuilder builder = new StringBuilder();

        final PrintWriter writer = new PrintWriter(new OutputStream() {
            @Override
            public void write(int oneByte) throws IOException {
                builder.append((char) oneByte);
            }
        });

        OsmChangeParser.parseElements(elems, changesetId, writer);
        writer.close();
        return builder.toString();
    }

    /**
     * Checks the number of elements in the database and returns true if is a
     * upload necessary.
     * 
     * @param context
     *            the context
     * @return true, if upload is necessary
     */
    public static boolean needToUpload(Context context) {
        final DataBaseHandler db = new DataBaseHandler(context);
        final List<DataElement> elems = db.getAllDataElements();
        return !elems.isEmpty();
    }

    /**
     * Returns a {@link HttpPost} containing the Changeset ID which is signed by
     * the OAuth {@link User}.
     * 
     * @param user
     *            The OAuth {@link User}.
     * @param id
     *            The Changeset ID.
     * @return The signed {@link HttpPost}.
     * @throws OsmException
     *             Indicates an failure in an osm progess.
     */
    private static HttpPost getUploadPost(User user, int id) throws OsmException {
        final OAuthParameters params = OAuthParameters.CURRENT;
        final OAuthConsumer consumer = new CommonsHttpOAuthConsumer(params.getConsumerKey(),
                params.getConsumerSecret());
        consumer.setTokenWithSecret(user.getOAuthToken(), user.getOauthTokenSecret());
        final HttpPost httpPost = new HttpPost(params.getScopeUrl() + "api/0.6/changeset/" + id + "/upload");
        try {
            consumer.sign(httpPost);
        } catch (OAuthMessageSignerException e) {
            throw new OsmException(e);
        } catch (OAuthExpectationFailedException e) {
            throw new OsmException(e);
        } catch (OAuthCommunicationException e) {
            throw new OsmException(e);
        }

        final BasicHttpParams httpParams = new BasicHttpParams();
        httpParams.setParameter("id", id);
        httpPost.setParams(httpParams);
        return httpPost;
    }

    /**
     * Returns a {@link CloseableUpload} containing all nessesary informations
     * for the upload to the OSM API.
     * 
     * @param user
     *            The {@link User} who uploads the Changeset.
     * @param changesetId
     *            The Changeset ID.
     * @param changesetXml
     *            The Changeset which should be uploaded.
     * @param callback
     *            The callback object for interaction with the
     *            {@link ResultReceiver}.
     * @return {@link CloseableUpload} object
     * @throws OsmException
     *             Indicates an failure in an osm progess.
     */
    public static CloseableUpload upload(User user, int changesetId, String changesetXml,
            Callback<Integer> callback) throws OsmException {
        try {
            final HttpPost request = getUploadPost(user, changesetId);

            // Setting the Entity
            final HttpEntity entity = new CallbackStringEntry(changesetXml, callback);
            request.setEntity(entity);

            return new CloseableUpload(request);
        } catch (UnsupportedEncodingException e) {
            throw new OsmException(e);
        }
    }

    /**
     * Returns a {@link HttpPut} which closes the Changeset with the given ID.
     * 
     * @param user
     *            The {@link User} account to sign the {@link HttpPut}.
     * @param changeSetId
     *            The Changeset ID.
     * @return The signed {@link HttpPut}.
     * @throws OsmException
     *             Indicates an failure in an osm progess.
     */
    private static HttpPut getChangeSetClose(User user, long changeSetId) throws OsmException {
        final OAuthParameters params = OAuthParameters.CURRENT;
        final OAuthConsumer consumer = new CommonsHttpOAuthConsumer(params.getConsumerKey(),
                params.getConsumerSecret());
        consumer.setTokenWithSecret(user.getOAuthToken(), user.getOauthTokenSecret());
        final HttpPut httpPut = new HttpPut(params.getScopeUrl() + "api/0.6/changeset/" + changeSetId + "/close");
        try {
            consumer.sign(httpPut);
        } catch (OAuthMessageSignerException e) {
            throw new OsmException(e);
        } catch (OAuthExpectationFailedException e) {
            throw new OsmException(e);
        } catch (OAuthCommunicationException e) {
            throw new OsmException(e);
        }
        final BasicHttpParams httpParams = new BasicHttpParams();
        httpParams.setParameter("id", changeSetId);
        httpPut.setParams(httpParams);
        return httpPut;
    }

    /**
     * Requests a Closure of a changesetId from the OSM-API.
     * 
     * @param user
     *            The user to request the Closure of the id
     * @param changesetId
     *            The Id of the changeSet which should be closed
     * @return The ClosableCloseRequest which sends the Request
     * @throws OsmException
     *             If the changesetId cannot be grabbed
     */
    public static CloseableCloseRequest closeId(final User user, final long changesetId) throws OsmException {
        final HttpPut request = getChangeSetClose(user, changesetId);
        return new CloseableCloseRequest(request);
    }

    /**
     * Returns a {@link HttpGet} containing the boundingbox and time.
     * 
     * @param time
     *            the time from where we are looking for new changeSets
     * @param min_lon
     *            lowest Longitude of the BoundingBox
     * @param min_lat
     *            lowest Latitude of the BoundingBox
     * @param max_lon
     *            Highest Longitude of the BoundingBox
     * @param max_lat
     *            highest Latitude of the BoundingBox
     * @return HttpGet with Params
     */
    private static HttpGet getChangesetGet(long time, double min_lon, double min_lat, double max_lon,
            double max_lat) {
        final OAuthParameters params = OAuthParameters.CURRENT;
        final HttpGet httpGet = new HttpGet(params.getScopeUrl() + "api/0.6/changesets");

        final BasicHttpParams httpParams = new BasicHttpParams();
        List<Double> bbox = new LinkedList<Double>();
        bbox.add(min_lon);
        bbox.add(min_lat);
        bbox.add(max_lon);
        bbox.add(max_lat);

        String timeformat = "yyyy-MM-dd'T'HH:mm:ss.SZZZZZ";
        final SimpleDateFormat dateformat = new SimpleDateFormat(timeformat);
        httpParams.setParameter("bbox", bbox);
        httpParams.setParameter("time", dateformat.format(new Date(time)));
        httpParams.setParameter("closed", true);

        httpGet.setParams(httpParams);
        return httpGet;
    }

    /**
     * Requests a list of closed changesets from the OSM-API.
     * 
     * @param time
     *            the time from where we are looking for new changeSets
     * @param min_lon
     *            lowest Longitude of the BoundingBox
     * @param min_lat
     *            lowest Latitude of the BoundingBox
     * @param max_lon
     *            Highest Longitude of the BoundingBox
     * @param max_lat
     *            highest Latitude of the BoundingBox
     * @return The ClosableCloseRequest which sends the Request
     * @throws OsmException
     *             If the changesetId cannot be grabbed
     */
    public static CloseableGetChangeSets getChangeSet(long time, double min_lon, double min_lat, double max_lon,
            double max_lat) throws OsmException {
        final HttpGet request = getChangesetGet(time, min_lon, min_lat, max_lon, max_lat);
        return new CloseableGetChangeSets(request);
    }

}