source: ComponentRegistry/trunk/ComponentRegistry/src/main/java/clarin/cmdi/componentregistry/rest/MDValidator.java @ 5549

Last change on this file since 5549 was 5549, checked in by olhsha@mpi.nl, 10 years ago

Added group service. Tested via the tomcat on loclahots (test URI and postman), old unit tests are adjusted and work well. Todo: retest on localhost tomcat, look at run-time exceptions, add new unit tests, adjust front-end

File size: 11.4 KB
Line 
1package clarin.cmdi.componentregistry.rest;
2
3import clarin.cmdi.componentregistry.ComponentRegistry;
4import clarin.cmdi.componentregistry.ComponentRegistryException;
5import clarin.cmdi.componentregistry.ComponentRegistryResourceResolver;
6import clarin.cmdi.componentregistry.Configuration;
7import clarin.cmdi.componentregistry.ItemNotFoundException;
8import clarin.cmdi.componentregistry.MDMarshaller;
9import clarin.cmdi.componentregistry.NullIdException;
10import clarin.cmdi.componentregistry.RegistrySpace;
11import clarin.cmdi.componentregistry.UserUnauthorizedException;
12import clarin.cmdi.componentregistry.components.CMDComponentSpec;
13import clarin.cmdi.componentregistry.components.CMDComponentType;
14import clarin.cmdi.componentregistry.model.BaseDescription;
15import clarin.cmdi.schema.cmd.Validator.Message;
16import clarin.cmdi.schema.cmd.ValidatorException;
17import java.io.ByteArrayInputStream;
18import java.io.ByteArrayOutputStream;
19import java.io.IOException;
20import java.io.InputStream;
21import java.net.MalformedURLException;
22import java.net.URL;
23import java.util.ArrayList;
24import java.util.Arrays;
25import java.util.Collection;
26import java.util.Collections;
27import java.util.List;
28import javax.xml.bind.JAXBException;
29import javax.xml.transform.stream.StreamSource;
30import org.slf4j.Logger;
31import org.slf4j.LoggerFactory;
32
33public class MDValidator implements Validator {
34
35    private final static Logger LOG = LoggerFactory.getLogger(MDValidator.class);
36    static final String MISMATCH_ERROR = "Cannot register component as a profile or vica versa.";
37    static final String COMPONENT_NOT_REGISTERED_ERROR = "referenced component is not registered or does not have a correct componentId: ";
38    static final String PARSE_ERROR = "Error in validation input file: ";
39    static final String SCHEMA_ERROR = "Error in reading general component schema: ";
40    static final String IO_ERROR = "Error while reading specification or general component schema: ";
41    static final String COMPONENT_NOT_REGISTERED_IN_APPROPRIATE_SPACE_ERROR = "referenced component cannot be found in the appropriate registry components: ";
42    static final String COMPONENT_REGISTRY_EXCEPTION_ERROR = "An exception occurred while accessing the component registry: ";
43    static final String ILLEGAL_ATTRIBUTE_NAME_ERROR = "Illegal attribute name: ";
44    static final String UNKNOWN_VALIDATION_ERROR = "Unknown validation error";
45    static final Collection<String> ILLEGAL_ATTRIBUTE_NAMES = Collections.unmodifiableCollection(Arrays.asList("ref", "ComponentId"));
46    private List<String> errorMessages = new ArrayList<String>();
47    private CMDComponentSpec spec = null;
48    private byte[] originalSpecBytes;
49    private final InputStream input;
50    private final BaseDescription description;
51    private final ComponentRegistry registry;
52    private final MDMarshaller marshaller;
53
54    /**
55     *
56     * @param input In order to validate the input is consumed. So use
57     * @see getCMDComponentSpec to get the parsed CMDComponentSpec.
58     * @param desc
59     * @param registry (registry you currently used)
60     * @param userRegistry can be null, We get user registry as well so we can
61     * give nice error messages if needed. Can be the same as
62     * @param registry
63     */
64    public MDValidator(InputStream input, BaseDescription description, ComponentRegistry registry, MDMarshaller marshaller) {
65        this.input = input;
66        this.description = description;
67        this.registry = registry;
68        this.marshaller = marshaller;
69    }
70
71    @Override
72    public List<String> getErrorMessages() {
73        return errorMessages;
74    }
75
76    @Override
77    public boolean validate() throws UserUnauthorizedException {
78        try {
79            clarin.cmdi.schema.cmd.Validator validator = new clarin.cmdi.schema.cmd.Validator(new URL(Configuration.getInstance().getGeneralComponentSchema()));
80            validator.setResourceResolver(new ComponentRegistryResourceResolver());
81            // We may need to reuse the input stream, so save it to a byte array first
82            originalSpecBytes = getBytesFromInputStream();
83            StreamSource source = new StreamSource(new ByteArrayInputStream(originalSpecBytes));
84            if (!validator.validateProfile(source)) {
85                final List<Message> validatorMessages = validator.getMessages();
86                if (validatorMessages.size() > 0) {
87                    for (Message message : validatorMessages) {
88                        errorMessages.add(PARSE_ERROR + message.getText());
89                    }
90                } else {
91                    errorMessages.add(PARSE_ERROR + UNKNOWN_VALIDATION_ERROR);
92                }
93            } else {
94                spec = unmarshalSpec(originalSpecBytes);
95                if (spec.isIsProfile() != description.isProfile()) {
96                    errorMessages.add(MISMATCH_ERROR);
97                }
98            }
99        } catch (MalformedURLException e) {
100            errorMessages.add(SCHEMA_ERROR + e.getMessage());
101            LOG.error(SCHEMA_ERROR, e);
102        } catch (JAXBException e) {
103            errorMessages.add(PARSE_ERROR + e.getMessage());
104            LOG.error(PARSE_ERROR, e);
105        } catch (ValidatorException e) {
106            errorMessages.add(PARSE_ERROR + e.getMessage());
107            LOG.error(PARSE_ERROR, e);
108        } catch (IOException e) {
109            errorMessages.add(IO_ERROR + e.getMessage());
110            LOG.error(IO_ERROR, e);
111        }
112        if (errorMessages.isEmpty()) {
113            try {
114                validateComponents(spec);
115            } catch (ComponentRegistryException e) {
116                errorMessages.add(COMPONENT_REGISTRY_EXCEPTION_ERROR + e);
117            } catch (ItemNotFoundException e2) {
118                errorMessages.add(COMPONENT_NOT_REGISTERED_ERROR + e2);
119            } catch (NullIdException e3) {
120                errorMessages.add(COMPONENT_NOT_REGISTERED_ERROR + e3);
121            }
122        }
123        return errorMessages.isEmpty();
124    }
125
126    private byte[] getBytesFromInputStream() throws IOException {
127        int len;
128        byte[] b = new byte[4096];
129        final ByteArrayOutputStream bOS = new ByteArrayOutputStream();
130
131        while ((len = input.read(b)) > 0) {
132            bOS.write(b, 0, len);
133        }
134
135        return bOS.toByteArray();
136    }
137
138    private void validateComponents(CMDComponentSpec componentSpec) throws ComponentRegistryException, UserUnauthorizedException, ItemNotFoundException, NullIdException {
139        validateComponents(Collections.singletonList(componentSpec.getCMDComponent()));
140    }
141
142    private void validateComponents(List<CMDComponentType> cmdComponents) throws ComponentRegistryException, UserUnauthorizedException, ItemNotFoundException, NullIdException {
143        for (CMDComponentType cmdComponentType : cmdComponents) {
144            this.validateDescribedComponents(cmdComponentType);
145            this.validateComponents(cmdComponentType.getCMDComponent());//Recursion
146        }
147    }
148
149    private void validateDescribedComponents(CMDComponentType cmdComponentType) throws ComponentRegistryException, UserUnauthorizedException, ItemNotFoundException, NullIdException {
150        this.checkComponentInSpace(cmdComponentType);
151    }
152
153    private void checkComponentInSpace(CMDComponentType cmdComponentType) throws ComponentRegistryException, UserUnauthorizedException, ItemNotFoundException, NullIdException {
154        if (isDefinedInSeparateFile(cmdComponentType)) {
155            String id = cmdComponentType.getComponentId();
156            if (id == null) {
157                String name = (cmdComponentType.getName() == null) ? "null" : cmdComponentType.getName();
158                throw new NullIdException("The component with the name " + name + " has a null id. :(");
159            }
160            CMDComponentSpec registeredComponent = registry.getMDComponent(id);
161            if (registeredComponent != null) {
162                String componentId = cmdComponentType.getComponentId();
163                Boolean isPublicB = registry.isItemPublic(id);// throws ItemNotFoundException
164                boolean isPublic = isPublicB.booleanValue();
165                if (isPublic) {  // if  a component is public, it is available for any registry
166                    return;
167                };
168                // a private component for a private registry is available only if its owner is the owner of the resgitry
169                if (registry.getRegistrySpace().equals(RegistrySpace.PRIVATE)) {
170                    Number registryOwnerId = registry.getRegistryOwner().getId();
171                    Number componentOwnerId = registry.getBaseDescriptionOwnerId(cmdComponentType.getComponentId());
172                    if (registryOwnerId.equals(componentOwnerId)) {
173                        return;
174                    };
175                    errorMessages.add(COMPONENT_NOT_REGISTERED_IN_APPROPRIATE_SPACE_ERROR + componentId + " (private registry)");
176                    return;
177
178                } else { // a private component in a group registry is availabe only if it belongs to the group
179                    if (registry.getRegistrySpace().equals(RegistrySpace.GROUP)) {
180                        if (registry.getGroupId() == null) {
181                            errorMessages.add(COMPONENT_REGISTRY_EXCEPTION_ERROR + "in the group space, the group id is null");
182                            return;
183                        }
184                        List<Number> componentGroupIds = registry.getItemGroups(cmdComponentType.getComponentId());
185                        if (componentGroupIds.contains(registry.getGroupId())) {
186                            return;
187                        }
188                        errorMessages.add(COMPONENT_NOT_REGISTERED_IN_APPROPRIATE_SPACE_ERROR + componentId + " (group registry) " + registry.getGroupId());
189                        return;
190                    }
191                    errorMessages.add(COMPONENT_NOT_REGISTERED_IN_APPROPRIATE_SPACE_ERROR + componentId + " (private component in public registry).");
192                    return;
193                }
194
195            };
196            errorMessages.add(COMPONENT_NOT_REGISTERED_ERROR + cmdComponentType.getComponentId());
197        }
198
199    }
200
201    private boolean isDefinedInSeparateFile(CMDComponentType cmdComponentType) {
202        return cmdComponentType.getName() == null;
203    }
204
205    /**
206     * Do not call before having called {@link #validate() }!
207     *
208     * @return the spec unmarshalled during {@link #validate() }. If this has
209     * not been called, returns null.
210     */
211    public CMDComponentSpec getCMDComponentSpec() {
212        return spec;
213    }
214
215    /**
216     * Creates a fresh (re-unmarshalled) copy of the specification this instance
217     * has validated. If you are not going to alter this copy, you can re-use
218     * and share the copy used during validation by getting it from {@link #getCMDComponentSpec()
219     * }. <em>Do not call before having called {@link #validate() }!</em>
220     *
221     * @return a freshly unmarshalled copy of the spec based on the bytes
222     * collected from the input stream passed to {@link #validate() }. If this
223     * has not been called, returns null.
224     * @throws JAXBException exception occurred while marshalling from the input
225     * bytes
226     * @see #validate()
227     * @see #getCMDComponentSpec()
228     */
229    public CMDComponentSpec getCopyOfCMDComponentSpec() throws JAXBException {
230        // Re-unmarshall original bytes
231        return unmarshalSpec(originalSpecBytes);
232
233
234    }
235
236    private CMDComponentSpec unmarshalSpec(byte[] inputBytes) throws JAXBException {
237        return marshaller.unmarshal(CMDComponentSpec.class, new ByteArrayInputStream(inputBytes), null);
238    }
239}
Note: See TracBrowser for help on using the repository browser.