/**
*
* Funf: Open Sensing Framework
* Copyright (C) 2010-2011 Nadav Aharony, Wei Pan, Alex Pentland.
* Acknowledgments: Alan Gardner
* Contact: nadav@media.mit.edu
*
* This file is part of Funf.
*
* Funf is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* Funf 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Funf. If not, see <http://www.gnu.org/licenses/>.
*
*/
package edu.mit.media.funf.pipeline;
import java.io.IOException;
import java.util.Map;
import android.content.Context;
import android.util.Log;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.TypeAdapter;
import com.google.gson.internal.Streams;
import com.google.gson.internal.bind.JsonTreeReader;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import edu.mit.media.funf.config.ConfigRewriteUtil;
import edu.mit.media.funf.config.ConfigurableTypeAdapterFactory;
import edu.mit.media.funf.config.DefaultRuntimeTypeAdapterFactory;
import edu.mit.media.funf.config.RuntimeTypeAdapterFactory;
import edu.mit.media.funf.util.LogUtil;
public class PipelineFactory implements RuntimeTypeAdapterFactory {
private RuntimeTypeAdapterFactory delegate;
/**
* Use the base class as the default class.
* @param context
* @param baseClass
*/
public PipelineFactory(Context context) {
this(context, BasicPipeline.class);
}
/**
* @param context
* @param baseClass
* @param defaultClass Setting this to null will cause a ParseException if the runtime type information is incorrect or unavailable.
*/
public PipelineFactory(Context context, Class<? extends Pipeline> defaultClass) {
assert context != null;
this.delegate = new DefaultRuntimeTypeAdapterFactory<Pipeline>(context, Pipeline.class, defaultClass, new ConfigurableTypeAdapterFactory());
}
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
TypeAdapter<T> delegateAdapter = delegate.create(gson, type);
if (delegateAdapter != null) {
delegateAdapter = new ScheduleAnnotatedTypeAdapter<T>(delegateAdapter);
}
return delegateAdapter;
}
private static class ScheduleAnnotatedTypeAdapter<T> extends TypeAdapter<T> {
private TypeAdapter<T> delegateAdapter;
private ScheduleAnnotatedTypeAdapter(TypeAdapter<T> delegateAdapter) {
this.delegateAdapter = delegateAdapter;
}
@Override
public void write(JsonWriter out, T value) throws IOException {
// Cannot determine what was annotated, and what was in schedules
delegateAdapter.write(out, value);
}
@Override
public T read(JsonReader in) throws IOException {
JsonObject el = Streams.parse(in).getAsJsonObject();
JsonObject schedules = new JsonObject();
// Inject "@schedule" annotation into existing schedules
// i.e. { "key": { schedule-object } } will be transformed to
// { "key": { "@schedule": { schedule-object } } }
if (el.has(ConfigRewriteUtil.SCHEDULES_FIELD_NAME)) {
JsonObject directSchedules = el.remove(
ConfigRewriteUtil.SCHEDULES_FIELD_NAME).getAsJsonObject();
for (Map.Entry<String,JsonElement> entry : directSchedules.entrySet()) {
if (entry.getValue().isJsonObject()) {
JsonObject subConfig = entry.getValue().getAsJsonObject();
JsonObject scheduleConfig = new JsonObject();
scheduleConfig.add(ConfigRewriteUtil.SCHEDULE,
subConfig.remove(ConfigRewriteUtil.SCHEDULE));
schedules.add(entry.getKey(), scheduleConfig);
}
}
}
// strip @schedule annotations from non-data entries (eg. archive, upload, etc)
for (Map.Entry<String,JsonElement> entry : el.entrySet()) {
if (ConfigRewriteUtil.DATA_FIELD_NAME.equals(entry.getKey()))
continue;
if (entry.getValue().isJsonObject()) {
JsonObject subConfig = entry.getValue().getAsJsonObject();
if (subConfig.has(ConfigRewriteUtil.SCHEDULE)) {
JsonObject scheduleConfig = new JsonObject();
scheduleConfig.add(ConfigRewriteUtil.SCHEDULE,
subConfig.remove(ConfigRewriteUtil.SCHEDULE));
schedules.add(entry.getKey(), scheduleConfig);
}
}
}
el.add(ConfigRewriteUtil.SCHEDULES_FIELD_NAME, schedules);
ConfigRewriteUtil.rewrite(el);
Log.d(LogUtil.TAG, el.toString());
T result = delegateAdapter.read(new JsonTreeReader(el));
return result;
}
}
@Override
public <T> Class<? extends T> getRuntimeType(JsonElement el, TypeToken<T> type) {
return delegate.getRuntimeType(el, type);
}
}