source: ComponentRegistry/trunk/ComponentRegistry/src/main/java/clarin/cmdi/componentregistry/CMDComponentSpecExpander.java @ 1562

Last change on this file since 1562 was 1562, checked in by twagoo, 13 years ago

Detect recursion when expanding profiles/components, and throw an exception if found.
+ a test for this

File size: 4.9 KB
Line 
1package clarin.cmdi.componentregistry;
2
3import clarin.cmdi.componentregistry.components.CMDComponentSpec;
4import clarin.cmdi.componentregistry.components.CMDComponentType;
5import java.util.ArrayList;
6import java.util.Collection;
7import java.util.HashSet;
8import java.util.List;
9import org.slf4j.Logger;
10import org.slf4j.LoggerFactory;
11
12/**
13 *
14 * @author Twan Goosen <twan.goosen@mpi.nl>
15 */
16public abstract class CMDComponentSpecExpander {
17
18    private final static Logger LOG = LoggerFactory.getLogger(CMDComponentSpecExpander.class);
19    protected final ComponentRegistry registry;
20
21    public CMDComponentSpecExpander(ComponentRegistry registry) {
22        this.registry = registry;
23    }
24
25    private void expandNestedComponent(List<CMDComponentType> cmdComponents) throws ComponentRegistryException {
26        expandNestedComponent(cmdComponents, new HashSet<String>());
27    }
28
29    private void expandNestedComponent(List<CMDComponentType> cmdComponents, Collection<String> path) throws ComponentRegistryException {
30        List<CMDComponentType> expanded = new ArrayList<CMDComponentType>();
31        for (CMDComponentType cmdComponentType : cmdComponents) {
32            String componentId = cmdComponentType.getComponentId();
33            if (componentId != null) {
34                if (path.contains(componentId)) {
35                    throw new ComponentRegistryException("Detected recursion in component specification: " + path.toString() + " already contains " + componentId);
36                } else {
37                    Collection<String> newPath = new HashSet<String>(path);
38                    newPath.add(componentId);
39                    // Use uncached components and profiles, because we expand and thus change them this change should not be in the cache.
40                    CMDComponentSpec spec = getUncachedComponent(componentId);
41                    if (spec != null) {
42                        CMDComponentType nested = getComponentTypeOfAComponent(spec);
43                        expandNestedComponent(nested.getCMDComponent(), newPath);
44                        overwriteAttributes(cmdComponentType, nested);
45                        expanded.add(nested);
46                    } else {
47                        // Spec could not be resolved
48                        LOG.warn("Could not resolve referenced component with id " + componentId);
49                        // Add spec itself, without futher expanding
50                        expanded.add(cmdComponentType);
51                    }
52                }
53            } else {
54                // No id = embedded component
55                expandNestedComponent(cmdComponentType.getCMDComponent(), path);
56                expanded.add(cmdComponentType);//no attributes overwritten
57            }
58        }
59        cmdComponents.clear();
60        cmdComponents.addAll(expanded);
61    }
62
63    private CMDComponentType getComponentTypeOfAComponent(CMDComponentSpec result) {
64        List<CMDComponentType> cmdComponents = result.getCMDComponent();
65        if (cmdComponents.size() != 1) {
66            LOG.error("Internal error: CMDComponentSpec which is not a profile can only have one "
67                    + "CMDComponentType (which is the description of the component itself).");
68        }
69        CMDComponentType cmdComponentType = cmdComponents.get(0);
70        return cmdComponentType;
71    }
72
73    /**
74     * Copying the cardinality specified in the referenceDeclaration over the values in the actual component.
75     */
76    private void overwriteAttributes(CMDComponentType referenceDeclaration, CMDComponentType nested) {
77        if (!referenceDeclaration.getCardinalityMax().isEmpty()) {
78            List<String> cardinalityMax = nested.getCardinalityMax();
79            cardinalityMax.clear();
80            cardinalityMax.addAll(referenceDeclaration.getCardinalityMax());
81        }
82        if (!referenceDeclaration.getCardinalityMin().isEmpty()) {
83            List<String> cardinalityMin = nested.getCardinalityMin();
84            cardinalityMin.clear();
85            cardinalityMin.addAll(referenceDeclaration.getCardinalityMin());
86        }
87        nested.setComponentId(referenceDeclaration.getComponentId()); // Setting componentId for better xsd generation.
88    }
89
90    protected CMDComponentSpec expandComponent(String componentId) throws ComponentRegistryException {
91        // Use uncached components and profiles, because we expand and thus change them this change should not be in the cache.
92        CMDComponentSpec result = getUncachedComponent(componentId);//registry.getUncachedComponent(componentId);
93        CMDComponentType cmdComponentType = getComponentTypeOfAComponent(result);
94        expandNestedComponent(cmdComponentType.getCMDComponent());
95        return result;
96    }
97
98    protected CMDComponentSpec expandProfile(String profileId) throws ComponentRegistryException {
99        // Use uncached components and profiles, because we expand and thus change them this change should not be in the cache.
100        CMDComponentSpec result = getUncachedProfile(profileId);//registry.getUncachedProfile(profileId);
101        List<CMDComponentType> cmdComponents = result.getCMDComponent();
102        expandNestedComponent(cmdComponents);
103        return result;
104    }
105
106    /**
107     * Get uncached component from "this" registry and possibly from public registry. Note: "this" registry can be a user registry.
108     * @param componentId
109     */
110    protected abstract CMDComponentSpec getUncachedComponent(String componentId) throws ComponentRegistryException;
111
112    protected abstract CMDComponentSpec getUncachedProfile(String profileId) throws ComponentRegistryException;
113}
Note: See TracBrowser for help on using the repository browser.