org.androidtransfuse.processor.ManifestManager.java Source code

Java tutorial

Introduction

Here is the source code for org.androidtransfuse.processor.ManifestManager.java

Source

/**
 * Copyright 2011-2015 John Ericksen
 *
 * 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.androidtransfuse.processor;

import org.androidtransfuse.TransfuseAnalysisException;
import org.androidtransfuse.config.TransfuseAndroidModule;
import org.androidtransfuse.model.Mergeable;
import org.androidtransfuse.model.manifest.*;
import org.androidtransfuse.util.AndroidLiterals;
import org.androidtransfuse.util.Logger;
import org.apache.commons.beanutils.PropertyUtils;

import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * @author John Ericksen
 */
@Singleton
public class ManifestManager {

    private final List<Application> applications = new ArrayList<Application>();
    private final String manifestPackage;
    private final List<Activity> activities = new ArrayList<Activity>();
    private final List<Receiver> broadcastReceivers = new ArrayList<Receiver>();
    private final List<Service> services = new ArrayList<Service>();
    private final List<UsesPermission> usesPermissions = new ArrayList<UsesPermission>();
    private final List<UsesFeature> usesFeatures = new ArrayList<UsesFeature>();
    private final List<Permission> permissions = new ArrayList<Permission>();
    private final Logger log;
    private UsesSDK usesSdk;

    @Inject
    public ManifestManager(@Named(TransfuseAndroidModule.ORIGINAL_MANIFEST) Manifest originalManifest, Logger log) {
        this.log = log;
        this.manifestPackage = originalManifest.getApplicationPackage();
    }

    public void addApplication(Application application) {
        log.debug("Adding to manifest: " + application);
        this.applications.add(application);
    }

    public void addPermission(Permission permission) {
        try {
            log.debug("Adding to manifest: " + permission);
            updateMergeTags(Permission.class, permission);
            permissions.add(permission);
        } catch (MergerException e) {
            throw new TransfuseAnalysisException("Unable to Merge UsesPermission", e);
        }
    }

    public void addUsesFeature(UsesFeature usesFeature) {
        try {
            log.debug("Adding to manifest: " + usesFeature);
            updateMergeTags(UsesFeature.class, usesFeature);
            usesFeatures.add(usesFeature);
        } catch (MergerException e) {
            throw new TransfuseAnalysisException("Unable to Merge UsesFeature", e);
        }
    }

    public void addUsesPermission(UsesPermission usesPermission) {
        try {
            log.debug("Adding to manifest: " + usesPermission);
            updateMergeTags(UsesPermission.class, usesPermission);
            usesPermissions.add(usesPermission);
        } catch (MergerException e) {
            throw new TransfuseAnalysisException("Unable to Merge UsesPermission", e);
        }
    }

    public void setUsesSdk(UsesSDK usesSdk) {
        log.debug("Adding to manifest: " + usesSdk);
        this.usesSdk = usesSdk;
    }

    public void addActivity(Activity activity) {
        try {
            log.debug("Adding to manifest: " + activity);
            updateMergeTags(Activity.class, activity);
            updateMergeTags(IntentFilter.class, activity.getIntentFilters());
            updateMergeTags(MetaData.class, activity.getMetaData());
            this.activities.add(activity);
        } catch (MergerException e) {
            throw new TransfuseAnalysisException("Unable to Merge Activity", e);
        }
    }

    public void addBroadcastReceiver(Receiver broadcastReceiver) {
        try {
            log.debug("Adding to manifest: " + broadcastReceiver);
            updateMergeTags(Receiver.class, broadcastReceiver);
            updateMergeTags(IntentFilter.class, broadcastReceiver.getIntentFilters());
            updateMergeTags(MetaData.class, broadcastReceiver.getMetaData());
            this.broadcastReceivers.add(broadcastReceiver);
        } catch (MergerException e) {
            throw new TransfuseAnalysisException("Unable to Merge Broadcast Receiver", e);
        }
    }

    private <T extends Mergeable> void updateMergeTags(Class<T> clazz, List<T> mergeableCollection)
            throws MergerException {
        for (T mergeable : mergeableCollection) {
            updateMergeTags(clazz, mergeable);
        }
    }

    public void addService(Service service) {
        try {
            log.debug("Adding to manifest: " + service);
            updateMergeTags(Service.class, service);
            updateMergeTags(IntentFilter.class, service.getIntentFilters());
            updateMergeTags(MetaData.class, service.getMetaData());
            this.services.add(service);
        } catch (MergerException e) {
            throw new TransfuseAnalysisException("Unable to Merge Service", e);
        }
    }

    public Manifest getManifest() throws MergerException {
        Manifest manifest = new Manifest();
        manifest.setApplicationPackage(manifestPackage);

        Application localApplication;

        if (applications.isEmpty()) {
            localApplication = new Application();
            localApplication.setName(AndroidLiterals.APPLICATION.getName());
        } else {
            localApplication = applications.get(0);
        }

        //todo: do multiple applications result in an error?

        updateMergeTags(Application.class, localApplication);

        localApplication.getActivities().addAll(activities);
        localApplication.getReceivers().addAll(broadcastReceivers);
        localApplication.getServices().addAll(services);

        manifest.getApplications().add(localApplication);

        manifest.getUsesPermissions().addAll(usesPermissions);

        manifest.getUsesFeatures().addAll(usesFeatures);

        manifest.getPermissions().addAll(permissions);

        if (usesSdk != null) {
            manifest.getUsesSDKs().add(usesSdk);
        }

        manifest.updatePackages();

        return manifest;
    }

    private <T extends Mergeable> void updateMergeTags(Class<T> clazz, T mergeable) throws MergerException {
        try {
            mergeable.setGenerated(true);

            BeanInfo beanInfo = Introspector.getBeanInfo(clazz);

            for (PropertyDescriptor propertyDescriptor : beanInfo.getPropertyDescriptors()) {
                Method readMethod = propertyDescriptor.getReadMethod();
                Method writeMethod = propertyDescriptor.getWriteMethod();

                Merge mergeAnnotation = findAnnotation(Merge.class, writeMethod, readMethod);
                Object property = PropertyUtils.getProperty(mergeable, propertyDescriptor.getName());

                if (mergeAnnotation != null && property != null) {
                    mergeable.addMergeTag(mergeAnnotation.value());
                }
            }
        } catch (IntrospectionException e) {
            throw new MergerException(e);
        } catch (InvocationTargetException e) {
            throw new MergerException(e);
        } catch (NoSuchMethodException e) {
            throw new MergerException(e);
        } catch (IllegalAccessException e) {
            throw new MergerException(e);
        }
    }

    private <T extends Annotation> T findAnnotation(Class<T> annotationClass, Method... methods) {
        T annotation = null;
        if (methods != null) {
            for (Method method : methods) {
                if (annotation == null && method != null && method.isAnnotationPresent(annotationClass)) {
                    annotation = method.getAnnotation(annotationClass);
                }
            }
        }
        return annotation;
    }
}