<commit_before>package org.apache.felix.ipojo.everest.ipojo;

import org.apache.felix.ipojo.ComponentInstance;
import org.apache.felix.ipojo.Factory;
import org.apache.felix.ipojo.InstanceStateListener;
import org.apache.felix.ipojo.architecture.Architecture;
import org.apache.felix.ipojo.everest.core.Everest;
import org.apache.felix.ipojo.everest.impl.DefaultReadOnlyResource;
import org.apache.felix.ipojo.everest.impl.DefaultRelation;
import org.apache.felix.ipojo.everest.impl.ImmutableResourceMetadata;
import org.apache.felix.ipojo.everest.services.*;
import org.apache.felix.ipojo.handlers.dependency.DependencyDescription;
import org.apache.felix.ipojo.handlers.dependency.DependencyHandlerDescription;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;

import java.lang.ref.WeakReference;
import java.util.Hashtable;

import static org.apache.felix.ipojo.everest.ipojo.IpojoRootResource.*;

/**
 * '/ipojo/instance/$name/dependency/$is' resource.
 */
public class ServiceDependencyResource extends DefaultReadOnlyResource {

    public ServiceDependencyResource(InstanceResource instance, DependencyDescription dependency) {
        super(instance.getDependencies().getPath().addElements(dependency.getId()));
    }

    // TODO implement dependency state listener
    @Override
    public boolean isObservable() {
        return true;
    }
}<commit_msg>everest-ipojo: service dependency resource got metadata + relations<commit_after>package org.apache.felix.ipojo.everest.ipojo;

import org.apache.felix.ipojo.everest.core.Everest;
import org.apache.felix.ipojo.everest.impl.DefaultReadOnlyResource;
import org.apache.felix.ipojo.everest.impl.DefaultRelation;
import org.apache.felix.ipojo.everest.impl.ImmutableResourceMetadata;
import org.apache.felix.ipojo.everest.services.*;
import org.apache.felix.ipojo.handlers.dependency.Dependency;
import org.apache.felix.ipojo.handlers.dependency.DependencyDescription;
import org.apache.felix.ipojo.util.DependencyModel;
import org.apache.felix.ipojo.util.DependencyStateListener;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;

import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static org.apache.felix.ipojo.everest.ipojo.IpojoRootResource.PATH_TO_OSGI_SERVICES;
import static org.apache.felix.ipojo.util.DependencyModel.*;

/**
 * '/ipojo/instance/$name/dependency/$id' resource.
 */
// TODO Register as a dependency listener as soon as iPOJO permits it.
public class ServiceDependencyResource extends DefaultReadOnlyResource implements DependencyStateListener {

    private WeakReference<DependencyDescription> m_description;

    public ServiceDependencyResource(InstanceResource instance, DependencyDescription description) {
        super(instance.getDependencies().getPath().addElements(description.getId()),
                new ImmutableResourceMetadata.Builder()
                        .set("id", description.getId())
                        .set("specification", description.getSpecification()) // May become mutable is future iPOJO releases?
                        .set("isNullable", description.supportsNullable())
                        .set("isProxy", description.isProxy())
                        .set("defaultImplementation", description.getDefaultImplementation())
                                // All other attributes are considered dynamic
                        .build());
        m_description = new WeakReference<DependencyDescription>(description);
    }

    @Override
    public ResourceMetadata getMetadata() {
        ResourceMetadata m = super.getMetadata();
        DependencyDescription d = m_description.get();
        if (d == null) {
            return m;
        } else {
            //@SuppressWarnings("unchecked")
            List refs = d.getServiceReferences();
            List used = d.getUsedServices();
            return new ImmutableResourceMetadata.Builder()
                    .set("state", stateToString(d.getState()))
                    .set("filter", d.getFilter())
                    .set("policy", policyToString(d.getPolicy()))
                    .set("comparator", d.getComparator())
                    .set("isAggregate", d.isMultiple())
                    .set("isOptional", d.isOptional())
                    .set("isFrozen", d.isFrozen())
                    .build();
        }
    }

    @Override
    public List<Relation> getRelations() {
        List<Relation> r = super.getRelations();
        DependencyDescription d = m_description.get();
        if (d == null) {
            return r;
        } else {
            r = new ArrayList<Relation>(r);
            @SuppressWarnings("unchecked")
            List<ServiceReference<?>> matching = d.getServiceReferences();
            if (matching != null) {
                for(ServiceReference<?> s : matching) {
                    String id = String.valueOf(s.getProperty(Constants.SERVICE_ID));
                    r.add(new DefaultRelation(
                            PATH_TO_OSGI_SERVICES.addElements(id),
                            Action.READ,
                            String.format("matchingService[%s]", id),
                            String.format("Matching service with id '%s'", id)));
                }
            }
            @SuppressWarnings("unchecked")
            List<ServiceReference<?>> used = d.getUsedServices();
            for(ServiceReference<?> s : used) {
                String id = String.valueOf(s.getProperty(Constants.SERVICE_ID));
                r.add(new DefaultRelation(
                        PATH_TO_OSGI_SERVICES.addElements(id),
                        Action.READ,
                        String.format("usedService[%s]", id),
                        String.format("Used service with id '%s'", id)));
            }
            return Collections.unmodifiableList(r);
        }
    }

    @Override
    public boolean isObservable() {
        return true;
    }

    @Override
    public <A> A adaptTo(Class<A> clazz) {
        if (clazz == DependencyModel.class) {
            return clazz.cast(getDependency(m_description.get()));
        } else if (clazz == DependencyDescription.class) {
            return clazz.cast(m_description.get());
        } else {
            return super.adaptTo(clazz);
        }
    }

    public void validate(DependencyModel dependency) {
        // Fire UPDATED event
        Everest.postResource(ResourceEvent.UPDATED, this);
    }

    public void invalidate(DependencyModel dependency) {
        // Fire UPDATED event
        Everest.postResource(ResourceEvent.UPDATED, this);
    }

    private static String policyToString(int policy) {
        switch (policy) {
            case DYNAMIC_BINDING_POLICY:
                return "DYNAMIC_BINDING";
            case STATIC_BINDING_POLICY:
                return "STATIC_BINDING";
            case DYNAMIC_PRIORITY_BINDING_POLICY:
                return "DYNAMIC_PRIORITY_BINDING";
            default:
                return "CUSTOMIZED"; // Optimistic!
        }
    }

    private static String stateToString(int state) {
        switch (state) {
            case BROKEN:
                return "BROKEN";
            case UNRESOLVED:
                return "UNRESOLVED";
            case RESOLVED:
                return "RESOLVED";
            default:
                return "unknown";
        }
    }

    // WARN: This is a hack!
    private static Dependency getDependency(DependencyDescription description) {
        if (description == null) {
            return null;
        }
        Field shunt = null;
        try {
            shunt = DependencyDescription.class.getDeclaredField("m_dependency");
            shunt.setAccessible(true);
            return (Dependency) shunt.get(description);
        } catch (Exception e) {
            throw new IllegalStateException("cannot get component instance", e);
        } finally {
            if (shunt != null) {
                shunt.setAccessible(false);
            }
        }
    }
}
{'fraction_non_alphanumeric': 0.10338899803536346, 'fraction_numerical': 0.0, 'mean_word_length': 2.358762886597938, 'pattern_counts': {'":': 0, '<': 16, '<?xml version=': 0, '>': 16, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4159206', 'n_tokens_mistral': 2230, 'n_tokens_neox': 2165, 'n_words': 402}