Changeset 2347


Ignore:
Timestamp:
11/13/12 08:57:19 (12 years ago)
Author:
twagoo
Message:

Recursion check now happens on copy of spec so that original spec remains unchanged
Fixes #223

Location:
ComponentRegistry/trunk/ComponentRegistry/src
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • ComponentRegistry/trunk/ComponentRegistry/src/main/java/clarin/cmdi/componentregistry/CMDComponentSpecExpander.java

    r1753 r2347  
    2626    public void expandNestedComponent(List<CMDComponentType> cmdComponents, String id) throws ComponentRegistryException {
    2727        expandNestedComponent(cmdComponents, new HashSet<String>(Collections.singleton(id)));
    28     }
    29 
    30     public void expandNestedComponent(List<CMDComponentType> cmdComponents) throws ComponentRegistryException {
    31         expandNestedComponent(cmdComponents, new HashSet<String>());
    3228    }
    3329
  • ComponentRegistry/trunk/ComponentRegistry/src/main/java/clarin/cmdi/componentregistry/rest/ComponentRegistryRestService.java

    r1993 r2347  
    4545import javax.ws.rs.core.StreamingOutput;
    4646import javax.ws.rs.core.UriInfo;
     47import javax.xml.bind.JAXBException;
    4748import org.slf4j.Logger;
    4849import org.slf4j.LoggerFactory;
     
    7273     *
    7374     * TODO: Replace all calls to getRegistry that use this by calls using ComponentStatus
     75     *
    7476     * @param userSpace
    7577     * @return
     
    181183            if ("xml".equalsIgnoreCase(rawType)) {
    182184                result = new StreamingOutput() {
    183 
    184185                    @Override
    185186                    public void write(OutputStream output) throws IOException, WebApplicationException {
     
    194195            } else if ("xsd".equalsIgnoreCase(rawType)) {
    195196                result = new StreamingOutput() {
    196 
    197197                    @Override
    198198                    public void write(OutputStream output) throws IOException, WebApplicationException {
     
    616616            if ("xml".equalsIgnoreCase(rawType)) {
    617617                result = new StreamingOutput() {
    618 
    619618                    @Override
    620619                    public void write(OutputStream output) throws IOException, WebApplicationException {
     
    629628            } else if ("xsd".equalsIgnoreCase(rawType)) {
    630629                result = new StreamingOutput() {
    631 
    632630                    @Override
    633631                    public void write(OutputStream output) throws IOException, WebApplicationException {
     
    795793                CMDComponentSpec spec = validator.getCMDComponentSpec();
    796794                try {
    797                     // Expand to check for recursion
    798                     registry.getExpander().expandNestedComponent(spec.getCMDComponent(), desc.getId());
     795                    checkForRecursion(validator, registry, desc);
    799796
    800797                    // Add profile
     
    827824    }
    828825
     826    /**
     827     *
     828     * @param validator
     829     * @param registry
     830     * @param desc
     831     * @throws ComponentRegistryException if recursion is detected or something goes wrong while trying to detect recursion
     832     */
     833    private void checkForRecursion(MDValidator validator, ComponentRegistry registry, AbstractDescription desc) throws ComponentRegistryException {
     834        try {
     835            // Expand to check for recursion. Operate on copy so that original does not get expanded.
     836            final CMDComponentSpec specCopy = validator.getCopyOfCMDComponentSpec();
     837            // In case of recursion, the following will throw a ComponentRegistryException
     838            registry.getExpander().expandNestedComponent(specCopy.getCMDComponent(), desc.getId());
     839        } catch (JAXBException ex) {
     840            throw new ComponentRegistryException("Unmarshalling failed while preparing recursion detection", ex);
     841        }
     842    }
     843
    829844    private Response registerComment(InputStream input, ComponentRegistry registry, boolean userspace,
    830845            AbstractDescription description, Principal principal, UserCredentials userCredentials) {
  • ComponentRegistry/trunk/ComponentRegistry/src/main/java/clarin/cmdi/componentregistry/rest/MDValidator.java

    r1860 r2347  
    2929
    3030public class MDValidator implements Validator {
    31    
     31
    3232    private final static Logger LOG = LoggerFactory.getLogger(MDValidator.class);
    3333    static final String MISMATCH_ERROR = "Cannot register component as a profile or vica versa.";
     
    4343    private List<String> errorMessages = new ArrayList<String>();
    4444    private CMDComponentSpec spec = null;
     45    private byte[] originalSpecBytes;
    4546    private final InputStream input;
    4647    private final AbstractDescription description;
     
    6566        this.publicRegistry = publicRegistry;
    6667    }
    67    
     68
    6869    @Override
    6970    public List<String> getErrorMessages() {
    7071        return errorMessages;
    7172    }
    72    
     73
    7374    @Override
    7475    public boolean validate() {
     
    7778            validator.setResourceResolver(new ComponentRegistryResourceResolver());
    7879            // We may need to reuse the input stream, so save it to a byte array first
    79             byte[] inputBytes = getBytesFromInputStream();
    80             StreamSource source = new StreamSource(new ByteArrayInputStream(inputBytes));
     80            originalSpecBytes = getBytesFromInputStream();
     81            StreamSource source = new StreamSource(new ByteArrayInputStream(originalSpecBytes));
    8182            if (!validator.validateProfile(source)) {
    8283                final List<Message> validatorMessages = validator.getMessages();
     
    8990                }
    9091            } else {
    91                 spec = MDMarshaller.unmarshal(CMDComponentSpec.class, new ByteArrayInputStream(inputBytes), null);
     92                spec = unmarshalSpec(originalSpecBytes);
    9293                if (spec.isIsProfile() != description.isProfile()) {
    9394                    errorMessages.add(MISMATCH_ERROR);
     
    113114        return errorMessages.isEmpty();
    114115    }
    115    
     116
    116117    private byte[] getBytesFromInputStream() throws IOException {
    117118        int len;
    118119        byte[] b = new byte[4096];
    119120        final ByteArrayOutputStream bOS = new ByteArrayOutputStream();
    120        
     121
    121122        while ((len = input.read(b)) > 0) {
    122123            bOS.write(b, 0, len);
    123124        }
    124        
     125
    125126        return bOS.toByteArray();
    126127    }
    127    
     128
    128129    private void validateComponents(List<CMDComponentType> cmdComponents) throws ComponentRegistryException {
    129130        for (CMDComponentType cmdComponentType : cmdComponents) {
     
    132133        }
    133134    }
    134    
     135
    135136    private void validateDescribedComponents(CMDComponentType cmdComponentType) throws ComponentRegistryException {
    136137        checkPublicComponents(cmdComponentType);
    137138    }
    138    
     139
    139140    private void checkPublicComponents(CMDComponentType cmdComponentType) throws ComponentRegistryException {
    140141        if (isDefinedInSeparateFile(cmdComponentType)) {
     
    161162                    }
    162163                }
    163                
     164
    164165            }
    165166        }
    166167    }
    167    
     168
    168169    private boolean isDefinedInSeparateFile(CMDComponentType cmdComponentType) {
    169170        return cmdComponentType.getName() == null;
    170171    }
    171    
     172
     173    /**
     174     * Do not call before having called {@link #validate() }!
     175     *
     176     * @return the spec unmarshalled during {@link #validate() }. If this has not been called, returns null.
     177     */
    172178    public CMDComponentSpec getCMDComponentSpec() {
    173179        return spec;
    174180    }
     181
     182    /**
     183     * Creates a fresh (re-unmarshalled) copy of the specification this instance has validated. If you are not going to alter this copy,
     184     * you can re-use and share the copy used during validation by getting it from {@link #getCMDComponentSpec() }.
     185     * <em>Do not call before having called {@link #validate() }!</em>
     186     *
     187     * @return a freshly unmarshalled copy of the spec based on the bytes collected from the input stream passed to {@link #validate() }.
     188     * If this has not been called, returns null.
     189     * @throws JAXBException exception occurred while marshalling from the input bytes
     190     * @see #validate()
     191     * @see #getCMDComponentSpec()
     192     */
     193    public CMDComponentSpec getCopyOfCMDComponentSpec() throws JAXBException {
     194        // Re-unmarshall original bytes
     195        return unmarshalSpec(originalSpecBytes);
     196    }
     197
     198    private static CMDComponentSpec unmarshalSpec(byte[] inputBytes) throws JAXBException {
     199        return MDMarshaller.unmarshal(CMDComponentSpec.class, new ByteArrayInputStream(inputBytes), null);
     200    }
    175201}
  • ComponentRegistry/trunk/ComponentRegistry/src/test/java/clarin/cmdi/componentregistry/rest/MDValidatorTest.java

    r1993 r2347  
    44import clarin.cmdi.componentregistry.ComponentRegistryFactory;
    55import clarin.cmdi.componentregistry.ComponentStatus;
     6import clarin.cmdi.componentregistry.components.CMDComponentSpec;
    67import clarin.cmdi.componentregistry.impl.database.ComponentRegistryTestDatabase;
    78import clarin.cmdi.componentregistry.model.ComponentDescription;
     
    3738    @Test
    3839    public void testValidateSucces() {
    39         String profileContent = "";
    40         profileContent += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
    41         profileContent += "<CMD_ComponentSpec isProfile=\"true\" xmlns:xml=\"http://www.w3.org/XML/1998/namespace\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n";
    42         profileContent += "    xsi:noNamespaceSchemaLocation=\"general-component-schema.xsd\">\n";
    43         profileContent += "    <Header />\n";
    44         profileContent += "    <CMD_Component name=\"Actor\" CardinalityMin=\"0\" CardinalityMax=\"unbounded\">\n";
    45         profileContent += "        <CMD_Element name=\"Age\">\n";
    46         profileContent += "            <ValueScheme>\n";
    47         profileContent += "                <pattern>[23][0-9]</pattern>\n";
    48         profileContent += "            </ValueScheme>\n";
    49         profileContent += "        </CMD_Element>\n";
    50         profileContent += "    </CMD_Component>\n";
    51         profileContent += "</CMD_ComponentSpec>\n";
    52         InputStream input = new ByteArrayInputStream(profileContent.getBytes());
    53 
    54         ProfileDescription desc = ProfileDescription.createNewDescription();
    55         MDValidator validator = new MDValidator(input, desc, publicRegistry, null, publicRegistry);
     40        MDValidator validator = getValidProfileValidator();
    5641        assertTrue(validator.validate());
    5742    }
     
    222207        assertTrue(validator.validate());
    223208        assertEquals(0, validator.getErrorMessages().size());
    224 
     209    }
     210
     211    /**
     212     * Test of getCMDComponentSpec method, of class MDValidator.
     213     */
     214    @Test
     215    public void testGetCMDComponentSpec() throws Exception {
     216        String profileContent = getValidProfileString();
     217        InputStream input = new ByteArrayInputStream(profileContent.getBytes());
     218
     219        ProfileDescription desc = ProfileDescription.createNewDescription();
     220        MDValidator validator = new MDValidator(input, desc, publicRegistry, null, publicRegistry);
     221
     222        // Spec is created during validation, before it should be null
     223        assertNull(validator.getCMDComponentSpec());
     224        validator.validate();
     225
     226        // Get spec created during validation
     227        final CMDComponentSpec cmdComponentSpec = validator.getCMDComponentSpec();
     228        assertNotNull(cmdComponentSpec);
     229
     230        // Spec content should match XML
     231        assertTrue(cmdComponentSpec.isIsProfile());
     232        assertEquals("Actor", cmdComponentSpec.getCMDComponent().get(0).getName());
     233
     234        // Spec copy should be a freshly unmarshalled copy
     235        final CMDComponentSpec specCopy = validator.getCopyOfCMDComponentSpec();
     236        assertNotSame(cmdComponentSpec, specCopy);
     237
     238        // Content should still match XML
     239        assertTrue(specCopy.isIsProfile());
     240        assertEquals("Actor", specCopy.getCMDComponent().get(0).getName());
     241    }
     242
     243    private MDValidator getValidProfileValidator() {
     244        final String profileContent = getValidProfileString();
     245        InputStream input = new ByteArrayInputStream(profileContent.getBytes());
     246        ProfileDescription desc = ProfileDescription.createNewDescription();
     247        MDValidator validator = new MDValidator(input, desc, publicRegistry, null, publicRegistry);
     248        return validator;
     249    }
     250
     251    private String getValidProfileString() {
     252        String profileContent = "";
     253        profileContent += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
     254        profileContent += "<CMD_ComponentSpec isProfile=\"true\" xmlns:xml=\"http://www.w3.org/XML/1998/namespace\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n";
     255        profileContent += "    xsi:noNamespaceSchemaLocation=\"general-component-schema.xsd\">\n";
     256        profileContent += "    <Header />\n";
     257        profileContent += "    <CMD_Component name=\"Actor\" CardinalityMin=\"0\" CardinalityMax=\"unbounded\">\n";
     258        profileContent += "        <CMD_Element name=\"Age\">\n";
     259        profileContent += "            <ValueScheme>\n";
     260        profileContent += "                <pattern>[23][0-9]</pattern>\n";
     261        profileContent += "            </ValueScheme>\n";
     262        profileContent += "        </CMD_Element>\n";
     263        profileContent += "    </CMD_Component>\n";
     264        profileContent += "</CMD_ComponentSpec>\n";
     265        return profileContent;
    225266    }
    226267}
Note: See TracChangeset for help on using the changeset viewer.