/**
* Copyright 2011-2012 Universite Joseph Fourier, LIG, ADELE team
* 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 fr.imag.adele.apam.maven.plugin;
import java.util.HashSet;
import java.util.Set;
import org.apache.felix.bundlerepository.Capability;
import org.apache.felix.bundlerepository.RepositoryAdmin;
import fr.imag.adele.apam.CST;
import fr.imag.adele.apam.declarations.ComponentDeclaration;
import fr.imag.adele.apam.declarations.ImplementationDeclaration;
import fr.imag.adele.apam.declarations.InstanceDeclaration;
import fr.imag.adele.apam.declarations.PropertyDefinition;
import fr.imag.adele.apam.declarations.RelationDeclaration;
import fr.imag.adele.apam.declarations.Reporter;
import fr.imag.adele.apam.declarations.Reporter.Severity;
import fr.imag.adele.apam.declarations.SpecificationDeclaration;
import fr.imag.adele.apam.declarations.encoding.capability.CapabilityEncoder;
import fr.imag.adele.apam.declarations.references.components.ComponentReference;
import fr.imag.adele.apam.declarations.references.components.SpecificationReference;
import fr.imag.adele.apam.declarations.references.components.VersionedReference;
import fr.imag.adele.apam.declarations.repository.acr.ApamComponentRepository;
import fr.imag.adele.apam.declarations.repository.maven.MavenArtifactRepository;
import fr.imag.adele.apam.declarations.repository.maven.MavenProjectRepository;
import fr.imag.adele.apam.maven.plugin.validation.ValidationContext;
/**
* This class produces the ACR representation of the currently build project.
*
* It includes information regarding maven artifacts, component metadata and inferred
* capability requirements
*
* @author vega
*
*/
public class ApamComponentRepositoryBuilder {
private final RepositoryAdmin manager;
public ApamComponentRepositoryBuilder(ApamComponentRepository repository) {
this.manager = repository.getManager();
}
public String build(ValidationContext context, MavenProjectRepository project, Reporter reporter) {
if (manager == null) {
reporter.report(Severity.ERROR, "Cannot generate ACR content, invalid repository manager");
}
MavenArtifactRepository buildRepository = project.getBuildRepository();
StringBuilder result = new StringBuilder("<obr>\n");
/*
* Add capability to represent maven inforamtion
*/
Capability mavenCapability = CapabilityEncoder.builder(CST.MAVEN).
property(CST.GROUP_ID, buildRepository.getArtifact().getGroupId()).
property(CST.ARTIFACT_ID, buildRepository.getArtifact().getArtifactId()).
property(CST.VERSION, buildRepository.getArtifact().getVersion()).
build();
result.append(manager.getHelper().writeCapability(mavenCapability)).append("\n");
/*
* Add capabilities to represent component metadata
*/
CapabilityEncoder encoder = new CapabilityEncoder();
Set<ComponentReference<?>> processed = new HashSet<ComponentReference<?>>();
Set<VersionedReference<?>> referenced = new HashSet<VersionedReference<?>>();
for (ComponentDeclaration component : buildRepository.getComponents()) {
if (processed.contains(component.getReference())) {
reporter.report(Severity.WARNING,"Component " + component.getName() + " already defined in this build, declaration ignored "+component);
continue;
}
/*
* ACR repository is used at runtime by OBR Manager resolver. It uses direct searches over the
* properties of the component that ignore the property inheritance mechanisms of APAM.
*
* We need to simulate inheritance by copying properties from the ancestor declarations.
*
* NOTE notice that we create and modify an effective cloned declaration, we must be careful
* not to modify the original declaration in the project repository
*
*/
ComponentDeclaration group = context.getComponent(component.getGroupVersioned());
ComponentDeclaration effective = component.getEffectiveDeclaration(group);
/*
* Name property is not inherited directly, but renamed at each level
*/
ComponentDeclaration level = component;
while (level != null) {
if (level instanceof SpecificationDeclaration) {
effective.getProperties().put(CST.SPECNAME, level.getName());
}
if (level instanceof ImplementationDeclaration) {
effective.getProperties().put(CST.IMPLNAME, level.getName());
}
if (level instanceof InstanceDeclaration) {
effective.getProperties().put(CST.INSTNAME, level.getName());
}
level = context.getComponent(level.getGroupVersioned());
}
/*
* For unvalued properties we add default values, this allows filter to be evaluated even if no value
* is explicitly specified
*/
for (PropertyDefinition property : effective.getPropertyDefinitions()) {
String defaultValue = property.getDefaultValue();
String value = effective.getProperty(property.getName());
if (value == null && defaultValue != null) {
effective.getProperties().put(property.getName(),defaultValue);
}
}
/*
* Encode the effective declaration
*/
Capability encodedCapability = encoder.encode(effective,reporter);
if (encodedCapability != null) {
result.append(manager.getHelper().writeCapability(encodedCapability)).append("\n");
processed.add(component.getReference());
/*
* Update the list of referenced components
*/
if (component.getGroupVersioned() != null)
referenced.add(component.getGroupVersioned());
if (component instanceof ImplementationDeclaration) {
for (RelationDeclaration relation : component.getRelations()) {
if (relation.getTarget().as(SpecificationReference.class) != null) {
referenced.add(VersionedReference.any(relation.getTarget().as(SpecificationReference.class)));
}
}
}
}
}
/*
* Generate requirement for referenced components. In this way we can use the OBR resolver to install
* transitive dependencies
*/
for (VersionedReference<?> reference : referenced) {
result.append(manager.getHelper().writeRequirement(CapabilityEncoder.requirement(reference))).append("\n");
}
result.append("</obr> \n");
return result.toString();
}
}