source: ComponentRegistry/trunk/ComponentRegistry/src/main/java/clarin/cmdi/componentregistry/ComponentRegistryImpl.java @ 253

Last change on this file since 253 was 253, checked in by patdui, 14 years ago
  • return descriptions sorted by default
File size: 14.5 KB
Line 
1package clarin.cmdi.componentregistry;
2
3import java.io.File;
4import java.io.FileInputStream;
5import java.io.FileNotFoundException;
6import java.io.FileOutputStream;
7import java.io.IOException;
8import java.io.StringWriter;
9import java.io.Writer;
10import java.security.Principal;
11import java.util.ArrayList;
12import java.util.Collection;
13import java.util.Collections;
14import java.util.HashMap;
15import java.util.Iterator;
16import java.util.List;
17import java.util.Map;
18
19import javax.xml.bind.JAXBException;
20
21import org.apache.commons.io.FileUtils;
22import org.apache.commons.io.IOUtils;
23import org.apache.commons.io.filefilter.IOFileFilter;
24import org.apache.commons.io.filefilter.NameFileFilter;
25import org.apache.commons.io.filefilter.NotFileFilter;
26import org.apache.commons.io.filefilter.WildcardFileFilter;
27import org.apache.commons.lang.StringUtils;
28import org.slf4j.Logger;
29import org.slf4j.LoggerFactory;
30
31import clarin.cmdi.componentregistry.components.CMDComponentSpec;
32import clarin.cmdi.componentregistry.components.CMDComponentSpec.Header;
33import clarin.cmdi.componentregistry.model.AbstractDescription;
34import clarin.cmdi.componentregistry.model.ComponentDescription;
35import clarin.cmdi.componentregistry.model.ProfileDescription;
36
37public class ComponentRegistryImpl implements ComponentRegistry {
38
39    private static final String DESCRIPTION_FILE_NAME = "description.xml";
40
41    private final static Logger LOG = LoggerFactory.getLogger(ComponentRegistryImpl.class);
42
43    //bean will be injected
44    private Configuration configuration;
45
46    //cache fields
47    private Map<String, ComponentDescription> componentDescriptions;
48    private Map<String, ProfileDescription> profileDescriptions;
49    private Map<String, CMDComponentSpec> componentsCache;
50    private Map<String, CMDComponentSpec> profilesCache;
51
52    private final static ComponentRegistry INSTANCE = new ComponentRegistryImpl();
53
54    private ComponentRegistryImpl() {
55    }
56
57    public static ComponentRegistry getInstance() {
58        return INSTANCE;
59    }
60
61    public void setConfiguration(Configuration configuration) {
62        this.configuration = configuration;
63        initCache();
64    }
65
66    private void initCache() {
67        LOG.info("Initializing cache..");
68        LOG.info("CACHE: Reading and parsing all component descriptions.");
69        this.componentDescriptions = loadComponentDescriptions();
70        LOG.info("CACHE: Reading and parsing all profile descriptions.");
71        this.profileDescriptions = loadProfileDescriptions();
72        LOG.info("CACHE: Reading and parsing all components.");
73        this.componentsCache = loadComponents();
74        LOG.info("CACHE: Reading and parsing all profiles.");
75        this.profilesCache = loadProfiles();
76        LOG.info("CACHE: Loaded " + profileDescriptions.size() + " profile descriptions, " + profilesCache.size() + " profiles.");
77        LOG.info("CACHE: Loaded " + componentDescriptions.size() + " components descriptions, " + componentsCache.size() + " components.");
78        LOG.info("CACHE initialized. Any occured errors should be adressed, files could be corrupt."
79                + " Components and Profiles with errors will not be shown to users.");
80    }
81
82    private Map<String, CMDComponentSpec> loadProfiles() {
83        Map<String, CMDComponentSpec> result = new HashMap<String, CMDComponentSpec>();
84        for (Iterator<String> iter = profileDescriptions.keySet().iterator(); iter.hasNext();) {
85            String id = iter.next();
86            CMDComponentSpec spec = getUncachedProfile(id);
87            if (spec != null) {
88                result.put(id, spec);
89            } else {
90                iter.remove(); // cannot load actual profile so remove description from cache.
91            }
92        }
93        return result;
94    }
95
96    CMDComponentSpec getUncachedProfile(String id) {
97        File file = getProfileFile(id);
98        CMDComponentSpec spec = MDMarshaller.unmarshal(CMDComponentSpec.class, file);
99        return spec;
100    }
101
102    private Map<String, CMDComponentSpec> loadComponents() {
103        Map<String, CMDComponentSpec> result = new HashMap<String, CMDComponentSpec>();
104        for (Iterator<String> iter = componentDescriptions.keySet().iterator(); iter.hasNext();) {
105            String id = iter.next();
106            CMDComponentSpec spec = getUncachedComponent(id);
107            if (spec != null) {
108                result.put(id, spec);
109            } else {
110                iter.remove(); // cannot load actual component so remove description from cache.
111            }
112        }
113        return result;
114    }
115
116    CMDComponentSpec getUncachedComponent(String id) {
117        File file = getComponentFile(id);
118        CMDComponentSpec spec = MDMarshaller.unmarshal(CMDComponentSpec.class, file);
119        return spec;
120    }
121
122    private Map<String, ProfileDescription> loadProfileDescriptions() {
123        Collection files = FileUtils.listFiles(configuration.getProfileDir(), new WildcardFileFilter(DESCRIPTION_FILE_NAME),
124                DIRS_WITH_DESCRIPTIONS);
125        Map<String, ProfileDescription> result = new HashMap<String, ProfileDescription>();
126        for (Iterator iterator = files.iterator(); iterator.hasNext();) {
127            File file = (File) iterator.next();
128            ProfileDescription desc = MDMarshaller.unmarshal(ProfileDescription.class, file);
129            if (desc != null)
130                result.put(desc.getId(), desc);
131        }
132        return result;
133    }
134
135    private final static IOFileFilter DIRS_WITH_DESCRIPTIONS = new NotFileFilter(new NameFileFilter(Configuration.DELETED_DIR_NAME));
136
137    private Map<String, ComponentDescription> loadComponentDescriptions() {
138        Collection files = FileUtils.listFiles(getComponentDir(), new WildcardFileFilter(DESCRIPTION_FILE_NAME), DIRS_WITH_DESCRIPTIONS);
139        Map<String, ComponentDescription> result = new HashMap<String, ComponentDescription>();
140        for (Iterator iterator = files.iterator(); iterator.hasNext();) {
141            File file = (File) iterator.next();
142            ComponentDescription desc = MDMarshaller.unmarshal(ComponentDescription.class, file);
143            if (desc != null)
144                result.put(desc.getId(), desc);
145        }
146        return result;
147    }
148
149    private void updateCache(CMDComponentSpec spec, AbstractDescription description) {
150        if (description.isProfile()) {
151            profileDescriptions.put(description.getId(), (ProfileDescription) description);
152            profilesCache.put(description.getId(), spec);
153        } else {
154            componentDescriptions.put(description.getId(), (ComponentDescription) description);
155            componentsCache.put(description.getId(), spec);
156        }
157    }
158
159    private File getComponentDir() {
160        return configuration.getComponentDir();
161    }
162
163    public List<ComponentDescription> getComponentDescriptions() {
164        List<ComponentDescription> result = new ArrayList(componentDescriptions.values());
165        Collections.sort(result, ComponentDescription.COMPARE_ON_GROUP_AND_NAME);
166        return result;
167    }
168
169    public CMDComponentSpec getMDProfile(String profileId) {
170        CMDComponentSpec result = profilesCache.get(profileId);
171        return result;
172    }
173
174    public String getMDProfileAsXml(String profileId) {
175        String result = null;
176        File file = getProfileFile(profileId);
177        try {
178            result = IOUtils.toString(new FileInputStream(file));
179        } catch (FileNotFoundException e) {
180            LOG.error("Cannot retrieve file: " + file, e);
181        } catch (IOException e) {
182            LOG.error("Cannot retrieve content from file: " + file, e);
183        }
184        return result;
185    }
186
187    public String getMDProfileAsXsd(String profileId) {
188        CMDComponentSpec expandedSpec = CMDComponentSpecExpander.expandProfile(profileId, this);
189        return getXsd(expandedSpec);
190    }
191
192    private String getXsd(CMDComponentSpec expandedSpec) {
193        Writer writer = new StringWriter();
194        MDMarshaller.generateXsd(expandedSpec, writer);
195        return writer.toString();
196    }
197
198    public File getProfileFile(String profileId) {
199        String id = stripRegistryId(profileId);
200        File file = new File(configuration.getProfileDir(), id + File.separator + id + ".xml");
201        return file;
202    }
203
204    public CMDComponentSpec getMDComponent(String componentId) {
205        CMDComponentSpec result = componentsCache.get(componentId);
206        return result;
207    }
208
209    public String getMDComponentAsXml(String componentId) {
210        String result = null;
211        File file = getComponentFile(componentId);
212        try {
213            result = IOUtils.toString(new FileInputStream(file), "UTF-8");
214        } catch (FileNotFoundException e) {
215            LOG.error("Cannot retrieve file: " + file, e);
216        } catch (IOException e) {
217            LOG.error("Cannot retrieve content from file: " + file, e);
218        }
219        return result;
220    }
221
222    public String getMDComponentAsXsd(String componentId) {
223        CMDComponentSpec expandedSpec = CMDComponentSpecExpander.expandComponent(componentId, this);
224        return getXsd(expandedSpec);
225    }
226
227    public File getComponentFile(String componentId) {
228        String id = stripRegistryId(componentId);
229        File file = new File(configuration.getComponentDir(), id + File.separator + id + ".xml");
230        return file;
231    }
232
233    private String stripRegistryId(String id) {
234        return StringUtils.removeStart(id, REGISTRY_ID);
235    }
236
237    public List<ProfileDescription> getProfileDescriptions() {
238        List<ProfileDescription> result = new ArrayList(profileDescriptions.values());
239        Collections.sort(result, ProfileDescription.COMPARE_ON_NAME);
240        return result;
241    }
242
243    /**
244     * CMDComponentSpec and description are assumed to be valid.
245     */
246    public int registerMDComponent(ComponentDescription description, CMDComponentSpec spec) {
247        LOG.info("Attempt to register component: " + description);
248        return register(configuration.getComponentDir(), description, spec, "component");
249    }
250
251    /**
252     * CMDComponentSpec and description are assumed to be valid.
253     */
254    public int registerMDProfile(ProfileDescription profileDescription, CMDComponentSpec spec) {
255        LOG.info("Attempt to register profile: " + profileDescription);
256        return register(configuration.getProfileDir(), profileDescription, spec, "profile");
257    }
258
259    private int register(File storageDir, AbstractDescription description, CMDComponentSpec spec, String type) {
260        String strippedId = stripRegistryId(description.getId());
261        File dir = new File(storageDir, strippedId);
262        boolean success = false;
263        try {
264            boolean dirCreated = dir.mkdir();
265            if (dirCreated) {
266                writeDescription(dir, description);
267                enrichSpecHeader(spec, description);
268                writeCMDComponentSpec(dir, strippedId + ".xml", spec);
269                success = true;
270            }
271        } catch (IOException e) {
272            LOG.error("Register failed:", e);
273        } catch (JAXBException e) {
274            LOG.error("Register failed:", e);
275        } finally {
276            if (!success) {
277                LOG.info("Registration of " + type + " " + description + " unsuccessful. Cleaning up created folders.");
278                try {
279                    FileUtils.deleteDirectory(dir);
280                } catch (IOException e) {
281                    LOG.error("Error in registration. Cleaning up " + type + " failed: " + dir + " :", e);
282                }
283                return -1;
284            }
285        }
286        LOG.info("Succesfully registered a " + type + " in " + dir + " " + type + "= " + description);
287        updateCache(spec, description);
288        return 0;
289    }
290
291    private void enrichSpecHeader(CMDComponentSpec spec, AbstractDescription description) {
292        Header header = spec.getHeader();
293        header.setID(description.getId());
294        if (StringUtils.isEmpty(header.getName())) {
295            header.setName(description.getName());
296        }
297        if (StringUtils.isEmpty(header.getDescription())) {
298            header.setDescription(description.getDescription());
299        }
300
301    }
302
303    private void writeDescription(File profileDir, AbstractDescription description) throws IOException, JAXBException {
304        File metadataFile = new File(profileDir, DESCRIPTION_FILE_NAME);
305        FileOutputStream fos = new FileOutputStream(metadataFile);
306        MDMarshaller.marshal(description, fos);
307        LOG.info("Saving metadata is successful " + metadataFile);
308    }
309
310    private void writeCMDComponentSpec(File profileDir, String profileName, CMDComponentSpec spec) throws IOException, JAXBException {
311        File file = new File(profileDir, profileName);
312        FileOutputStream fos = new FileOutputStream(file);
313        MDMarshaller.marshal(spec, fos);
314        LOG.info("Saving profile/component is successful " + file);
315    }
316
317    public List<MDProfile> searchMDProfiles(String searchPattern) {
318        return Collections.EMPTY_LIST;
319    }
320
321    public void deleteMDProfile(String profileId, Principal principal) throws IOException, UserUnauthorizedException {
322        ProfileDescription desc = profileDescriptions.get(profileId);
323        if (desc != null) {
324            checkAuthorisation(desc, principal);
325            File profileFile = getProfileFile(profileId);
326            if (profileFile.exists()) {
327                FileUtils.moveDirectoryToDirectory(profileFile.getParentFile(), configuration.getProfileDeletionDir(), true);
328                profileDescriptions.remove(profileId);
329                profilesCache.remove(profileId);
330            } // else no profile so nothing to delete
331        }
332    }
333
334    private void checkAuthorisation(AbstractDescription desc, Principal principal) throws UserUnauthorizedException {
335        if (!principal.getName().equals(desc.getCreatorName())) {
336            throw new UserUnauthorizedException("Unauthorized operation user '" + principal.getName()
337                    + "' was not the creator of profile/component (" + desc + ").");
338        }
339    }
340
341    public void deleteMDComponent(String componentId, Principal principal) throws IOException, UserUnauthorizedException {
342        ComponentDescription desc = componentDescriptions.get(componentId);
343        if (desc != null) {
344            checkAuthorisation(desc, principal);
345            File componentFile = getComponentFile(componentId);
346            if (componentFile.exists()) {
347                FileUtils.moveDirectoryToDirectory(componentFile.getParentFile(), configuration.getComponentDeletionDir(), true);
348                componentDescriptions.remove(componentId);
349                componentsCache.remove(componentId);
350            } // else no component so nothing to delete
351        }
352    }
353
354}
Note: See TracBrowser for help on using the repository browser.