001/*
002 *  Copyright 2010 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.odf.course;
017
018import java.util.ArrayList;
019import java.util.Arrays;
020import java.util.Collections;
021import java.util.Date;
022import java.util.HashSet;
023import java.util.List;
024import java.util.Set;
025
026import javax.jcr.Node;
027
028import org.apache.commons.lang3.StringUtils;
029import org.apache.commons.lang3.ArrayUtils;
030
031import org.ametys.cms.content.external.ExternalizableMetadataHelper;
032import org.ametys.cms.content.external.ExternalizableMetadataProvider.ExternalizableMetadataStatus;
033import org.ametys.cms.repository.ModifiableDefaultContent;
034import org.ametys.odf.ProgramItem;
035import org.ametys.odf.courselist.CourseList;
036import org.ametys.odf.courselist.CourseListContainer;
037import org.ametys.odf.program.Program;
038import org.ametys.plugins.repository.AmetysRepositoryException;
039import org.ametys.plugins.repository.UnknownAmetysObjectException;
040import org.ametys.plugins.repository.metadata.CompositeMetadata;
041import org.ametys.plugins.repository.metadata.ModifiableCompositeMetadata;
042import org.ametys.plugins.repository.metadata.RichText;
043import org.ametys.plugins.repository.metadata.UnknownMetadataException;
044
045/**
046 * Class representing a {@link Course}
047 */
048public class Course extends ModifiableDefaultContent<CourseFactory> implements CourseListContainer, ProgramItem
049{
050    /** Name of metadata for parent course lists */
051    public static final String METADATA_PARENT_COURSE_LISTS = "parentCourseLists";
052    
053    /** Name of metadata for parent course lists */
054    public static final String METADATA_CHILD_COURSE_LISTS = "courseLists";
055    
056    /** Constants for elpCode Metadata* */
057    public static final String METADATA_ELP_CODE = "elpCode";
058
059    /** Mandatory Identifier to generate the CDM-fr id */
060    public static final String METADATA_CDM_CODE = "cdmCode";
061    
062    /** Constants for ects Metadata* */
063    public static final String METADATA_ECTS = "ects";
064
065    /** Constants for level Metadata* */
066    public static final String METADATA_LEVEL = "level";
067
068    /** Constants for description Metadata* */
069    public static final String METADATA_DESCRIPTION = "description";
070
071    /** Constants for objectives Metadata* */
072    public static final String METADATA_OBJECTIVES = "objectives";
073
074    /** Constants for nbHours Metadata* */
075    public static final String METADATA_NUMBER_OF_HOURS = "nbHours";
076
077    /** Constants for totalDurationOfCM Metadata* */
078    public static final String METADATA_CM_DURATION = "totalDurationOfCM";
079
080    /** Constants for totalDurationOfTP Metadata* */
081    public static final String METADATA_TP_DURATION = "totalDurationOfTP";
082
083    /** Constants for totalDurationOfTD Metadata* */
084    public static final String METADATA_TD_DURATION = "totalDurationOfTD";
085
086    /** Constants for neededPrerequisite Metadata* */
087    public static final String METADATA_NEEDED_PREREQUISITE = "neededPrerequisite";
088
089    /** Constants for formOfAssessment Metadata* */
090    public static final String METADATA_FORM_OF_ASSESSMENT = "formOfAssessment";
091    
092    /** Constants for syllabus Metadata* */
093    public static final String METADATA_SYLLABUS = "syllabus";
094
095    /** Constants for additionalInformations Metadata* */
096    public static final String METADATA_ADDITIONAL_INFORMATIONS = "additionalInformations";
097
098    /** Constants for erasmusCode Metadata* */
099    public static final String METADATA_ERASMUS_CODE = "erasmusCode";
100
101    /** Constants for teachingLocation Metadata* */
102    public static final String METADATA_TEACHING_LOCATION = "teachingLocation";
103
104    /** Constants for maxNumberOfStudents Metadata* */
105    public static final String METADATA_MAX_NUMBER_OF_STUDENTS = "maxNumberOfStudents";
106
107    /** Constants for teachingTerm Metadata* */
108    public static final String METADATA_TEACHING_TERM = "teachingTerm";
109
110    /** Constants for timeSlot Metadata* */
111    public static final String METADATA_TIME_SLOT = "timeSlot";
112
113    /** Constants for trainingCourseDuration Metadata* */
114    public static final String METADATA_TRAINING_COURSE_DURATION = "trainingCourseDuration";
115
116    /** Constants for teachingMethod Metadata* */
117    public static final String METADATA_FORMODFTEACHING_METHOD = "formofteachingMethod";
118    
119    /** Constants for formofteachingOrg Metadata* */
120    public static final String METADATA_FORMOFTEACHING_ORG = "formofteachingOrg";
121
122    /** Constants for formOfTeaching Metadata* */
123    public static final String METADATA_TEACHING_ACTIVITY = "teachingActivity";
124
125    /** Constants for teachingLanguage Metadata* */
126    public static final String METADATA_TEACHING_LANGUAGE = "teachingLanguage";
127
128    /** Constants for startDate Metadata* */
129    public static final String METADATA_START_DATE = "startDate";
130
131    /** Constants for keywords Metadata* */
132    public static final String METADATA_KEYWORDS = "keywords";
133
134    /** Constants for webLinkLabel Metadata* */
135    public static final String METADATA_WEB_LINK_LABEL = "webLinkLabel";
136
137    /** Constants for webLinkUrl Metadata* */
138    public static final String METADATA_WEB_LINK_URL = "webLinkUrl";
139
140    /** Constants for lomSheets Metadata */
141    public static final String METADATA_LOM_SHEETS = "lomSheets";
142
143    /** Constants for LOM Sheet URL metadata */
144    public static final String METADATA_LOM_SHEET_URL = "linkUrl";
145    
146    /** Constants for LOM Sheet label metadata */
147    public static final String METADATA_LOM_SHEET_LABEL = "linkLabel";
148    
149    /** Constants for contentType Metadata* */
150    public static final String METADATA_ORG_UNITS = "orgUnit";
151    
152    /** Constants for metadata 'personInCharge' */
153    public static final String METADATA_PERSONS_IN_CHARGE = "personInCharge";
154
155    /** Constants for metadata 'contact' */
156    public static final String METADATA_CONTACTS = "contact";
157    
158    /** Constants for metadata 'courseType' */
159    public static final String METADATA_COURSE_TYPE = "courseType";
160    
161    /** Constants for metadata 'bibliography' */
162    public static final String METADATA_BIBLIOGRAPHY = "bibliography";
163
164    /** Constants for metadata 'skills' */
165    public static final String METADATA_SKILLS = "skills";
166
167    /** Constants for metadata 'openToExchangeStudents' */
168    public static final String METADATA_OPEN_TO_EXCHANGE_STUDENTS = "openToExchangeStudents";
169
170    private String _contextPath;
171
172    /**
173     * Constructor.
174     * @param node the JCR Node.
175     * @param parentPath the parent path
176     * @param factory the corresponding factory.
177     */
178    public Course(Node node, String parentPath, CourseFactory factory)
179    {
180        super(node, parentPath, factory);
181    }
182
183    @Override
184    public List<CourseList> getCourseLists()
185    {
186        List<CourseList> children = new ArrayList<>();
187        
188        String[] childIds = getMetadataHolder().getStringArray(METADATA_CHILD_COURSE_LISTS, new String[0]);
189        for (String id : childIds)
190        {
191            try
192            {
193                CourseList child = _getFactory()._getResolver().resolveById(id);
194                children.add(child);
195            }
196            catch (UnknownAmetysObjectException e)
197            {
198                // Nothing
199            }
200        }
201        
202        return children;
203    }
204    
205    /**
206     * Get the parent course lists
207     * @return The parent course lists
208     */
209    public List<CourseList> getParentCourseLists()
210    {
211        List<CourseList> children = new ArrayList<>();
212        
213        String[] childIds = getMetadataHolder().getStringArray(METADATA_PARENT_COURSE_LISTS, new String[0]);
214        for (String id : childIds)
215        {
216            try
217            {
218                CourseList child = _getFactory()._getResolver().resolveById(id);
219                children.add(child);
220            }
221            catch (UnknownAmetysObjectException e)
222            {
223                // Nothing
224            }
225        }
226        
227        return children;
228    }
229
230    @Override
231    public boolean hasCourseLists()
232    {
233        return getMetadataHolder().getStringArray(METADATA_CHILD_COURSE_LISTS, new String[0]).length > 0;
234    }
235    
236    @Override
237    public boolean containsCourseList(String clId)
238    {
239        return ArrayUtils.contains(getMetadataHolder().getStringArray(METADATA_CHILD_COURSE_LISTS, new String[0]), clId);
240    }
241    
242    @Override
243    public Set<Program> getRootPrograms()
244    {
245        Set<Program> programs = new HashSet<>();
246        
247        String[] parentIds = getMetadataHolder().getStringArray(METADATA_PARENT_COURSE_LISTS, new String[0]);
248        for (String parentId : parentIds)
249        {
250            try
251            {
252                CourseList parentCL = _getFactory()._getResolver().resolveById(parentId);
253                programs.addAll(parentCL.getRootPrograms());
254            }
255            catch (UnknownAmetysObjectException e)
256            {
257                // parent not found 
258            }
259            
260        }
261        
262        return programs;
263    }
264    
265    /**
266     * Remove reference from local and remote metadata
267     * @param metadataName The metadata name
268     * @param value The value of reference to remove 
269     */
270    public void removeReference (String metadataName, String value)
271    {
272        String[] references = getMetadataHolder().getStringArray(metadataName, new String[0]);
273        List<String> refList = new ArrayList<>(Arrays.asList(references));
274        if (refList.contains(value))
275        {
276            refList.remove(value);
277        }
278        getMetadataHolder().setMetadata(metadataName, refList.toArray(new String[refList.size()]));
279        
280        String[] altReferences = getMetadataHolder().getStringArray(metadataName + ExternalizableMetadataHelper.ALTERNATIVE_SUFFIX, new String[0]);
281        List<String> altList = new ArrayList<>(Arrays.asList(altReferences));
282        if (altList.contains(value))
283        {
284            altList.remove(value);
285        }
286        getMetadataHolder().setMetadata(metadataName + ExternalizableMetadataHelper.ALTERNATIVE_SUFFIX, altList.toArray(new String[altList.size()]));
287    }
288    
289    // --------------------------------------------------------------------------------------//
290    // CONTACTS
291    // --------------------------------------------------------------------------------------//
292
293    /**
294     * Return the ids of "person in charge" contents binded to this course 
295     * @return The id of contents
296     */
297    public List<String> getPersonsInCharge()
298    {
299        String[] contacts = getMetadataHolder().getStringArray(METADATA_PERSONS_IN_CHARGE, new String[0]);
300        return new ArrayList<>(Arrays.asList(contacts));
301    }
302    
303    /**
304     * Return the ids of "contact" contents binded to this course 
305     * @return The id of contents
306     */
307    public List<String> getContacts()
308    {
309        String[] contacts = getMetadataHolder().getStringArray(METADATA_CONTACTS, new String[0]);
310        return new ArrayList<>(Arrays.asList(contacts));
311    }
312   
313    
314    // --------------------------------------------------------------------------------------//
315    // CONTEXT
316    // --------------------------------------------------------------------------------------//
317    /**
318     * Set the parent path for links and breadcrumb
319     * @param path the parent path
320     */
321    public void setContextPath (String path)
322    {
323        _contextPath = path;
324    }
325    
326    /**
327     * Get the parent path. Can be null.
328     * @return the parent path
329     */
330    public String getContextPath ()
331    {
332        return _contextPath;
333    }
334    
335    // --------------------------------------------------------------------------------------//
336    // ORGUNITS
337    // --------------------------------------------------------------------------------------//
338    /**
339     * Return the id of orgunit content binded to this course
340     * @return The id of contents
341     */
342    public List<String> getOrgUnits()
343    {
344        String[] orgunits = getMetadataHolder().getStringArray(METADATA_ORG_UNITS, new String[0]);
345        return new ArrayList<>(Arrays.asList(orgunits));
346    }
347
348    /**
349     * Add a orgunit to the referenced orgunits
350     * @param orgUnitId the id of orgunit content
351     */
352    public void addOrgUnit(String orgUnitId)
353    {
354        String[] orgunits = new String[0];
355        try
356        {
357            orgunits = ExternalizableMetadataHelper.getStringArray(getMetadataHolder(), METADATA_ORG_UNITS, ExternalizableMetadataStatus.LOCAL);
358        }
359        catch (UnknownMetadataException e)
360        {
361            // Nothing
362        }
363        
364        List<String> orgunitsList = new ArrayList<>(Arrays.asList(orgunits));
365        orgunitsList.add(orgUnitId);
366        
367        ExternalizableMetadataHelper.setLocalMetadata(getMetadataHolder(), METADATA_ORG_UNITS, orgunitsList.toArray(new String[orgunitsList.size()]), ExternalizableMetadataStatus.LOCAL);
368    }
369
370    /**
371     * Remove a orgunit from referenced orgunits
372     * @param orgUnitId the id of orgunit content
373     * @throws AmetysRepositoryException if failed to remove orgunit
374     */
375    public void removeOrgUnit(String orgUnitId) throws AmetysRepositoryException
376    {
377        String[] orgunits = new String[0];
378        try
379        {
380            orgunits = ExternalizableMetadataHelper.getStringArray(getMetadataHolder(), METADATA_ORG_UNITS, ExternalizableMetadataStatus.LOCAL);
381        }
382        catch (UnknownMetadataException e)
383        {
384            // Nothing
385        }
386        
387        List<String> orgunitsList = new ArrayList<>(Arrays.asList(orgunits));
388        if (orgunitsList.contains(orgUnitId))
389        {
390            orgunitsList.remove(orgUnitId);
391        }
392        
393        ExternalizableMetadataHelper.setLocalMetadata(getMetadataHolder(), METADATA_ORG_UNITS, orgunitsList.toArray(new String[orgunitsList.size()]), ExternalizableMetadataStatus.LOCAL);
394    }
395
396    /**
397     * Return the id of local orgunit contents binded to this course
398     * @return The id of contents
399     */
400    public List<String> getLocalOrgUnits()
401    {
402        try
403        {
404            String[] orgunits = ExternalizableMetadataHelper.getStringArray(getMetadataHolder(), METADATA_ORG_UNITS, ExternalizableMetadataStatus.LOCAL);
405            return new ArrayList<>(Arrays.asList(orgunits));
406        }
407        catch (UnknownMetadataException e)
408        {
409            return Collections.EMPTY_LIST;
410        }
411    }
412
413    /**
414     * Return the id of remote orgunit contents binded to this course
415     * @return The id of contents
416     */
417    public List<String> getRemoteOrgUnits()
418    {
419        try
420        {
421            String[] orgunits = ExternalizableMetadataHelper.getStringArray(getMetadataHolder(), METADATA_ORG_UNITS, ExternalizableMetadataStatus.EXTERNAL);
422            return new ArrayList<>(Arrays.asList(orgunits));
423        }
424        catch (UnknownMetadataException e)
425        {
426            return Collections.EMPTY_LIST;
427        }
428    }
429    
430    // --------------------------------------------------------------------------------------//
431    // GETTERS AND SETTERS
432    // --------------------------------------------------------------------------------------//
433    @Override
434    public String getCatalog()
435    {
436        return getMetadataHolder().getString(METADATA_CATALOG, null);
437    }
438    
439    @Override
440    public void setCatalog(String catalog) throws AmetysRepositoryException
441    {
442        getMetadataHolder().setMetadata(METADATA_CATALOG, catalog);
443    }
444    
445    /**
446     * Get the code of the {@link Course}
447     * @return the ELP code
448     */
449    public String getElpCode()
450    {
451        return getMetadataHolder().getString(METADATA_ELP_CODE, StringUtils.EMPTY);
452    }
453
454    /**
455     * Set the ELP code
456     * @param code the code to set
457     * @throws AmetysRepositoryException if failed to set metadata
458     */
459    public void setElpCode(String code) throws AmetysRepositoryException
460    {
461        if (_getFactory()._getSynchronizedMetadata(this).contains(METADATA_ELP_CODE))
462        {
463            ExternalizableMetadataHelper.setLocalMetadata(getMetadataHolder(), METADATA_ELP_CODE, code, ExternalizableMetadataStatus.LOCAL);
464        }
465        else
466        {
467            ExternalizableMetadataHelper.setMetadata(getMetadataHolder(), METADATA_ELP_CODE, code);
468        }
469    }
470    
471    @Override
472    public String getCode()
473    {
474        return getMetadataHolder().getString(METADATA_CODE, "");
475    }
476    
477    @Override
478    public void setCode(String code) throws AmetysRepositoryException
479    {
480        getMetadataHolder().setMetadata(METADATA_CODE, code);
481    }
482    
483    /**
484     * Get the description
485     * @return the description or null
486     */
487    public RichText getDescription()
488    {
489        try
490        {
491            return getMetadataHolder().getRichText(METADATA_DESCRIPTION);
492        }
493        catch (UnknownMetadataException e)
494        {
495            return null;
496        }
497    }
498
499    /**
500     * Get the objectives
501     * @return objectives
502     */
503    public RichText getObjectives()
504    {
505        try
506        {
507            return getMetadataHolder().getRichText(METADATA_OBJECTIVES);
508        }
509        catch (UnknownMetadataException e)
510        {
511            return null;
512        }
513    }
514
515    /**
516     * Get the CM duration
517     * @return the CM duration
518     */
519    public double getTotalDurationOfCM()
520    {
521        return getMetadataHolder().getDouble(METADATA_CM_DURATION, 0);
522    }
523
524    /**
525     * Get the TD duration
526     * @return the TD duration
527     */
528    public double getTotalDurationOfTD()
529    {
530        return getMetadataHolder().getDouble(METADATA_TD_DURATION, 0);
531    }
532
533    /**
534     * Get the TP duration
535     * @return the TP duration
536     * @throws AmetysRepositoryException if failed to get metadata
537     */
538    public double getTotalDurationOfTP() throws AmetysRepositoryException
539    {
540        return getMetadataHolder().getDouble(METADATA_TP_DURATION, 0);
541    }
542
543    /**
544     * Get the needed prerequisites
545     * @return the needed prerequisites or null if not set
546     */
547    public RichText getNeededPrerequisite()
548    {
549        try
550        {
551            return getMetadataHolder().getRichText(METADATA_NEEDED_PREREQUISITE);
552        }
553        catch (UnknownMetadataException e)
554        {
555            return null;
556        }
557    }
558
559    /**
560     * Get the formOfAssessment metadata
561     * @return the formOfAssessment or null if not set
562     */
563    public RichText getFormOfAssessment()
564    {
565        try
566        {
567            return getMetadataHolder().getRichText(METADATA_FORM_OF_ASSESSMENT);
568        }
569        catch (UnknownMetadataException e)
570        {
571            return null;
572        }
573    }
574    
575    /**
576     * Get the syllabus
577     * @return the syllabus or null if not set
578     */
579    public RichText getSyllabus()
580    {
581        try
582        {
583            return getMetadataHolder().getRichText(METADATA_SYLLABUS);
584        }
585        catch (UnknownMetadataException e)
586        {
587            return null;
588        }
589    }
590    
591    /**
592     * Get the list of LOM sheets
593     * @return the list of LOMsheets or an empty list
594     */
595    public Set<LOMSheet> getLOMSheets()
596    {
597        Set<LOMSheet> lomSheets = new HashSet<>();
598        try
599        {
600            CompositeMetadata metaLomSheets = getMetadataHolder().getCompositeMetadata(METADATA_LOM_SHEETS);
601            for (String metadataName : metaLomSheets.getMetadataNames())
602            {
603                CompositeMetadata metaLomSheet = metaLomSheets.getCompositeMetadata(metadataName);
604                LOMSheet lomSheet = new LOMSheet(metaLomSheet.getString(METADATA_LOM_SHEET_URL, ""), metaLomSheet.getString(METADATA_LOM_SHEET_LABEL, ""));
605                lomSheets.add(lomSheet);
606            }
607        }
608        catch (UnknownMetadataException e)
609        {
610            // Nothing to do
611        }
612        return lomSheets;
613    }
614    
615    /**
616     * Set the LOM sheets
617     * @param sheets The LOM sheets
618     */
619    public void setLOMSheets (Set<LOMSheet> sheets)
620    {
621        ModifiableCompositeMetadata metaLomSheets = getMetadataHolder().getCompositeMetadata(METADATA_LOM_SHEETS, true);
622        
623        // Remove old LOM sheets if exist
624        String[] chilNames = metaLomSheets.getMetadataNames();
625        for (String chilName : chilNames)
626        {
627            metaLomSheets.removeMetadata(chilName);
628        }
629        
630        int i = 1;
631        for (LOMSheet lomSheet : sheets)
632        {
633            ModifiableCompositeMetadata metaLomSheet = metaLomSheets.getCompositeMetadata(String.valueOf(i), true);
634            metaLomSheet.setMetadata(METADATA_LOM_SHEET_URL, lomSheet.getUrl());
635            metaLomSheet.setMetadata(METADATA_LOM_SHEET_LABEL, lomSheet.getLabel());
636            i++;
637        }
638    }
639    
640    /**
641     * Determines if the course has LOM sheet
642     * @param lomSheet The LOM sheet to test
643     * @return <code>true</code> if the course has LOM sheet
644     */
645    public boolean hasLOMSheet (LOMSheet lomSheet)
646    {
647        for (LOMSheet lom : getLOMSheets())
648        {
649            if (lom.getUrl().equals(lomSheet.getUrl()) && lom.getLabel().equals(lomSheet.getLabel()))
650            {
651                return true;
652            }
653        }
654        
655        return false;
656    }
657    
658    /**
659     * Get the additional information
660     * @return the additional information
661     */
662    public RichText getAdditionalInformations()
663    {
664        try
665        {
666            return getMetadataHolder().getRichText(METADATA_ADDITIONAL_INFORMATIONS);
667        }
668        catch (UnknownMetadataException e)
669        {
670            return null;
671        }
672    }
673
674    /**
675     * Get the Erasmus code
676     * @return the Erasmus code
677     */
678    public String getErasmusCode()
679    {
680        return getMetadataHolder().getString(METADATA_ERASMUS_CODE, StringUtils.EMPTY);
681    }
682
683    /**
684     * Get the teaching location
685     * @return the teaching location
686     */
687    public String[] getTeachingLocation()
688    {
689        return getMetadataHolder().getStringArray(METADATA_TEACHING_LOCATION, ArrayUtils.EMPTY_STRING_ARRAY);
690    }
691
692    /**
693     * Set the teaching location
694     * @param teachingLocation the teaching location to set
695     * @throws AmetysRepositoryException if failed to set metadata
696     */
697    public void setTeachingLocation(String[] teachingLocation) throws AmetysRepositoryException
698    {
699        getMetadataHolder().setMetadata(Course.METADATA_TEACHING_LOCATION, teachingLocation);
700    }
701
702    /**
703     * Get the ECTS
704     * @return the ECTS
705     */
706    public double getEcts()
707    {
708        return getMetadataHolder().getDouble(METADATA_ECTS, 0);
709    }
710
711    /**
712     * Get the number of hours
713     * @return the number of hours
714     */
715    public double getNumberOfHours()
716    {
717        return getMetadataHolder().getDouble(METADATA_NUMBER_OF_HOURS, 0);
718    }
719
720    /**
721     * Get the effectives
722     * @return the effectives
723     * @throws AmetysRepositoryException if failed to get metadata
724     */
725    public String getMaxNumberOfStudents()
726    {
727        return getMetadataHolder().getString(METADATA_MAX_NUMBER_OF_STUDENTS, StringUtils.EMPTY);
728    }
729
730    /**
731     * Get the teaching term
732     * @return the teaching term
733     */
734    public String getTeachingTerm()
735    {
736        return getMetadataHolder().getString(METADATA_TEACHING_TERM, StringUtils.EMPTY);
737    }
738
739    /**
740     * Get the level
741     * @return the level
742     */
743    public String getLevel()
744    {
745        return getMetadataHolder().getString(METADATA_LEVEL, StringUtils.EMPTY);
746    }
747
748    /**
749     * Get the teaching method
750     * @return the teaching method
751     */
752    public String getFormOfTeachingMethod()
753    {
754        return getMetadataHolder().getString(METADATA_FORMODFTEACHING_METHOD, StringUtils.EMPTY);
755    }
756
757    /**
758     * Get the teaching organizations
759     * @return the teaching organizations
760     */
761    public String[] getFormOfTeachingOrgs()
762    {
763        return getMetadataHolder().getStringArray(METADATA_FORMOFTEACHING_ORG, ArrayUtils.EMPTY_STRING_ARRAY);
764    }
765
766    /**
767     * Get the teaching activity
768     * @return the teaching activity
769     */
770    public String getTeachingActivity()
771    {
772        return getMetadataHolder().getString(METADATA_TEACHING_ACTIVITY, StringUtils.EMPTY);
773    }
774
775    /**
776     * Get the teaching language
777     * @return the teaching language
778     */
779    public String[] getTeachingLanguage()
780    {
781        return getMetadataHolder().getStringArray(METADATA_TEACHING_LANGUAGE, ArrayUtils.EMPTY_STRING_ARRAY);
782    }
783
784    /**
785     * Get the start date
786     * @return the start date
787     */
788    public Date getStartDate()
789    {
790        return getMetadataHolder().getDate(METADATA_START_DATE, null);
791    }
792
793    /**
794     * Get the time slot
795     * @return the time slot
796     */
797    public String getTimeSlot()
798    {
799        return getMetadataHolder().getString(METADATA_TIME_SLOT, StringUtils.EMPTY);
800    }
801
802    /**
803     * Get the keywords
804     * @return the keywords
805     */
806    public String[] getKeywords()
807    {
808        return getMetadataHolder().getStringArray(METADATA_KEYWORDS, ArrayUtils.EMPTY_STRING_ARRAY);
809    }
810
811    /**
812     * Get the web link label
813     * @return the web link label
814     */
815    public String getWebLinkLabel()
816    {
817        return getMetadataHolder().getString(METADATA_WEB_LINK_LABEL, StringUtils.EMPTY);
818    }
819
820    /**
821     * Get the web link URL
822     * @return the web link URL
823     */
824    public String getWebLinkUrl()
825    {
826        return getMetadataHolder().getString(METADATA_WEB_LINK_URL, StringUtils.EMPTY);
827    }
828
829    /**
830     * Get the course type (nature)
831     * @return the course type
832     */
833    public String getCourseType()
834    {
835        return getMetadataHolder().getString(METADATA_COURSE_TYPE, StringUtils.EMPTY);
836    }
837
838    /**
839     * Get the bibliography
840     * @return the bibliography
841     */
842    public RichText getBibliography()
843    {
844        try
845        {
846            return getMetadataHolder().getRichText(METADATA_BIBLIOGRAPHY);
847        }
848        catch (UnknownMetadataException e)
849        {
850            return null;
851        }
852    }
853    
854    /**
855     * Get the skills
856     * @return the skills
857     */
858    public RichText getSkills()
859    {
860        try
861        {
862            return getMetadataHolder().getRichText(METADATA_SKILLS);
863        }
864        catch (UnknownMetadataException e)
865        {
866            return null;
867        }
868    }
869    
870    /**
871     * Is open to exchange students
872     * @return <code>true</code> if the course is open to exchange students
873     */
874    public boolean isOpenToExchangeStudents()
875    {
876        return getMetadataHolder().getBoolean(METADATA_OPEN_TO_EXCHANGE_STUDENTS, false);
877    }
878    
879    // --------------------------------------------------------------------------------------//
880    // CDM-fr
881    // --------------------------------------------------------------------------------------//
882    @Override
883    public String getCDMId()
884    {
885        return "FRUAI" + _getFactory()._getRootOrgUnitRNE() + "CO" + getCode();
886    }
887    
888    @Override
889    public String getCdmCode()
890    {
891        return getMetadataHolder().getString(CDM_CODE, "");
892    }
893    
894    @Override
895    public void setCdmCode(String cdmCode) 
896    {
897        getMetadataHolder().setMetadata(CDM_CODE, cdmCode);
898    }
899}