net.naonedbus.manager.impl.ParkingPublicManager.java Source code

Java tutorial

Introduction

Here is the source code for net.naonedbus.manager.impl.ParkingPublicManager.java

Source

/**
 * Copyright (C) 2013 Romain Guefveneu.
 *   
 *  This file is part of naonedbus.
 *   
 *  Naonedbus is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *  
 *  Naonedbus is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package net.naonedbus.manager.impl;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Stack;

import net.naonedbus.bean.Equipement;
import net.naonedbus.bean.async.ParkingPublicTaskInfo;
import net.naonedbus.bean.parking.pub.ParkingPublic;
import net.naonedbus.manager.Unschedulable;
import net.naonedbus.rest.controller.impl.ParkingPublicsController;

import org.joda.time.DateTime;
import org.json.JSONException;

import android.content.ContentResolver;
import android.content.Context;
import android.os.Handler;
import android.os.Message;

public class ParkingPublicManager implements Unschedulable<ParkingPublicTaskInfo> {

    private static final String LOG_TAG = ParkingPublicManager.class.getSimpleName();

    private static final int CACHE_LIMITE_MINUTES = 15;
    private static ParkingPublicManager sInstance;

    private List<ParkingPublic> mCache;
    private DateTime mDateLimit;

    private Thread mParkingsThread;
    private final Stack<ParkingPublicTaskInfo> mParkingsTasks;
    private final Object mLock = new Object();

    public static synchronized ParkingPublicManager getInstance() {
        if (sInstance == null) {
            sInstance = new ParkingPublicManager();
        }

        return sInstance;
    }

    private ParkingPublicManager() {
        this.mCache = new ArrayList<ParkingPublic>();
        this.mParkingsTasks = new Stack<ParkingPublicTaskInfo>();
    }

    /**
     * Charger les donnes et grer le cache.
     * 
     * @throws IOException
     * @throws JSONException
     */
    private void init(final Context context) throws IOException, JSONException {
        final DateTime now = new DateTime();

        if (this.mCache.isEmpty() || now.isAfter(this.mDateLimit)) {
            final ParkingPublicsController controller = new ParkingPublicsController();
            this.mCache.clear();
            this.mCache = controller.getAll(context.getResources());
            this.mDateLimit = now.plusMinutes(CACHE_LIMITE_MINUTES);
            fillParkings(context.getContentResolver(), this.mCache);
        }
    }

    /**
     * Rcuprer les parkings publics.
     * 
     * @return La liste des parkings publics
     * @throws IOException
     * @throws JSONException
     */
    public List<ParkingPublic> getAll(final Context context) throws IOException, JSONException {
        init(context);
        return mCache;
    }

    /**
     * Rcuprer un parking public selon son id, si disponible en cache.
     * 
     * @param id
     *            L'id du parking.
     * @return Le parking s'il est disponible, {@code null} sinon.
     */
    public ParkingPublic getFromCache(final int id) {
        for (final ParkingPublic parkingPublic : mCache) {
            if (parkingPublic.getId().equals(id)) {
                return parkingPublic;
            }
        }
        return null;
    }

    /**
     * Ajouter les informations complmentaires des parkings publics contenues
     * dans l'quipement en base correspondant.
     * 
     * @param contentResolver
     * @param parkingsPublics
     */
    private void fillParkings(final ContentResolver contentResolver, final List<ParkingPublic> parkingsPublics) {
        final EquipementManager equipementManager = EquipementManager.getInstance();
        final List<Equipement> equipementsParkings = equipementManager.getParkings(contentResolver,
                EquipementManager.SousType.PARKING_PUBLIC);

        for (final ParkingPublic parkingPublic : parkingsPublics) {
            Equipement foundEquipement = null;
            for (final Equipement equipement : equipementsParkings) {
                if (parkingPublic.getId().equals(equipement.getId())) {
                    foundEquipement = equipement;
                    fillParking(parkingPublic, equipement);
                }
            }
            // Optimisation
            if (foundEquipement != null) {
                equipementsParkings.remove(foundEquipement);
            }
        }

    }

    /**
     * Complter les donnes d'un parking public par celles de l'quipement
     * correspondant.
     * 
     * @param parkingPublic
     * @param equipement
     */
    private void fillParking(final ParkingPublic parkingPublic, final Equipement equipement) {
        parkingPublic.setNom(equipement.getNom());
        parkingPublic.setLatitude(equipement.getLatitude());
        parkingPublic.setLongitude(equipement.getLongitude());
        parkingPublic.setAdresse(equipement.getAdresse());
        parkingPublic.setTelephone(equipement.getTelephone());
        parkingPublic.setUrl(equipement.getTelephone());
    }

    /**
     * Programmer la rcupration d'un parking de manire asynchrone.
     * 
     * @param contentResolver
     * @param idParking
     *            L'id du parking  rcuprer.
     * @param callback
     *            Un {@code Handler} receptionnant le resultat dans {@code obj}
     *            sous forme de {@code ParkingPublic} .
     * @return
     */
    public ParkingPublicTaskInfo scheduleGetParkingPublic(final Context context, final int idParking,
            final Handler callback) {
        final ParkingPublicTaskInfo task = new ParkingPublicTaskInfo(context, idParking, callback);
        mParkingsTasks.push(task);

        if (mParkingsThread == null || !mParkingsThread.isAlive()) {
            mParkingsThread = new Thread(parkingsLoader);
            mParkingsThread.start();
        } else if (mParkingsThread.getState().equals(Thread.State.TIMED_WAITING)) {
            synchronized (mLock) {
                mLock.notify();
            }
        }

        return task;
    }

    @Override
    public void unschedule(final ParkingPublicTaskInfo task) {
        mParkingsTasks.remove(task);
    }

    /**
     * Tche de chargement d'un parking de manire asynchrone.
     */
    private final Runnable parkingsLoader = new Runnable() {

        @Override
        public void run() {

            final Iterator<ParkingPublicTaskInfo> iterator = mParkingsTasks.iterator();
            ParkingPublic parking;
            ParkingPublicTaskInfo task;
            Handler handler;
            Message message;

            while (iterator.hasNext()) {
                task = mParkingsTasks.pop();

                try {
                    init(task.getContext());
                    parking = getFromCache(task.getTag());
                } catch (final IOException e) {
                    parking = null;
                } catch (final JSONException e) {
                    parking = null;
                }

                handler = task.getHandler();
                message = handler.obtainMessage();
                message.obj = parking;
                message.sendToTarget();

                if (mParkingsTasks.isEmpty()) {
                    synchronized (mLock) {
                        try {
                            mLock.wait(2000);
                        } catch (final InterruptedException e) {
                        }
                    }
                }
            }
        }
    };
}