001/*
002 *  Copyright 2012 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.plugins.linkdirectory.repository;
017
018import java.io.InputStream;
019import java.util.ArrayList;
020import java.util.Date;
021import java.util.List;
022
023import javax.jcr.Node;
024import javax.jcr.NodeIterator;
025import javax.jcr.PathNotFoundException;
026import javax.jcr.RepositoryException;
027import javax.jcr.Value;
028
029import org.apache.commons.lang3.ArrayUtils;
030import org.apache.commons.lang3.StringUtils;
031
032import org.ametys.core.group.GroupIdentity;
033import org.ametys.core.user.UserIdentity;
034import org.ametys.plugins.linkdirectory.Link;
035import org.ametys.plugins.repository.AmetysObject;
036import org.ametys.plugins.repository.AmetysRepositoryException;
037import org.ametys.plugins.repository.MovableAmetysObject;
038import org.ametys.plugins.repository.RepositoryConstants;
039import org.ametys.plugins.repository.RepositoryIntegrityViolationException;
040import org.ametys.plugins.repository.jcr.DefaultTraversableAmetysObject;
041import org.ametys.plugins.repository.metadata.BinaryMetadata;
042import org.ametys.plugins.repository.metadata.ModifiableBinaryMetadata;
043import org.ametys.plugins.repository.metadata.ModifiableCompositeMetadata;
044import org.ametys.web.repository.SiteAwareAmetysObject;
045import org.ametys.web.repository.site.Site;
046
047/**
048 * Repository implementation of a directory link.
049 */
050public class DefaultLink extends DefaultTraversableAmetysObject<DefaultLinkFactory> implements Link, SiteAwareAmetysObject, MovableAmetysObject
051{
052
053    /** Constant for URL property. */
054    public static final String PROPERTY_URL = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":url";
055
056    /** Constant for id of provider of dynamic information. */
057    public static final String PROPERTY_DYNAMIC_INFO_PROVIDER = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":dynamic-information";
058
059    /** Constant for internal URL property. */
060    public static final String PROPERTY_INTERNAL_URL = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":internal-url";
061
062    /** Constant for URL type property. */
063    public static final String PROPERTY_URLTYPE = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":url-type";
064
065    /** Constant for title property. */
066    public static final String PROPERTY_TITLE = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":title";
067
068    /** Constant for title property. */
069    public static final String PROPERTY_CONTENT = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":content";
070
071    /** Constant for URL alternative property. */
072    public static final String PROPERTY_URL_ALTERNATIVE = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":url-alternative";
073
074    /** Constant for picture type property. */
075    public static final String PROPERTY_PICTURE_TYPE = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":picture-type";
076
077    /** Constant for picture data property. */
078    public static final String PROPERTY_PICTURE = "picture";
079
080    /** Constant for picture id property. */
081    public static final String PROPERTY_PICTURE_ID = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":picture-id";
082
083    /** Constant for picture alternative property. */
084    public static final String PROPERTY_PICTURE_ALTERNATIVE = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":picture-alternative";
085
086    /** Constant for themes property. */
087    public static final String PROPERTY_THEMES = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":themes";
088
089    /** Constant for grant-any-user property. */
090    public static final String PROPERTY_GRANT_ANY_USER = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":grant-any-user";
091
092    /** Constant for granted-users node. */
093    public static final String NODE_NAME_GRANTED_USERS = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":granted-users";
094
095    /** Constant for granted-users node. */
096    public static final String NODE_NAME_GRANTED_USER = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":granted-user";
097
098    /** Constant for granted-groups node. */
099    public static final String NODE_NAME_GRANTED_GROUPS = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":granted-groups";
100
101    /** Constant for granted-group node. */
102    public static final String NODE_NAME_GRANTED_GROUP = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":granted-group";
103
104    /**
105     * Create a {@link DefaultLink}.
106     * 
107     * @param node the node backing this {@link AmetysObject}.
108     * @param parentPath the parent path in the Ametys hierarchy.
109     * @param factory the {@link DefaultLinkFactory} which creates the
110     *            AmetysObject.
111     */
112    public DefaultLink(Node node, String parentPath, DefaultLinkFactory factory)
113    {
114        super(node, parentPath, factory);
115    }
116
117    @Override
118    public String getUrl() throws AmetysRepositoryException
119    {
120        try
121        {
122            return getNode().getProperty(PROPERTY_URL).getString();
123        }
124        catch (PathNotFoundException e)
125        {
126            return null;
127        }
128        catch (RepositoryException e)
129        {
130            throw new AmetysRepositoryException("Error getting the URL property.", e);
131        }
132    }
133
134    @Override
135    public void setUrl(LinkType urlType, String url) throws AmetysRepositoryException
136    {
137        try
138        {
139            getNode().setProperty(PROPERTY_URLTYPE, urlType.toString());
140            getNode().setProperty(PROPERTY_URL, url);
141        }
142        catch (RepositoryException e)
143        {
144            throw new AmetysRepositoryException("Error setting the URL property.", e);
145        }
146    }
147
148    @Override
149    public String getInternalUrl() throws AmetysRepositoryException
150    {
151        try
152        {
153            return getNode().getProperty(PROPERTY_INTERNAL_URL).getString();
154        }
155        catch (PathNotFoundException e)
156        {
157            return null;
158        }
159        catch (RepositoryException e)
160        {
161            throw new AmetysRepositoryException("Error getting the internal URL property.", e);
162        }
163    }
164
165    @Override
166    public void setInternalUrl(String url) throws AmetysRepositoryException
167    {
168        try
169        {
170            getNode().setProperty(PROPERTY_INTERNAL_URL, url);
171        }
172        catch (RepositoryException e)
173        {
174            throw new AmetysRepositoryException("Error setting the internal URL property.", e);
175        }
176    }
177
178    @Override
179    public LinkType getUrlType() throws AmetysRepositoryException
180    {
181        try
182        {
183            return LinkType.valueOf(getNode().getProperty(PROPERTY_URLTYPE).getString());
184        }
185        catch (RepositoryException e)
186        {
187            throw new AmetysRepositoryException("Unable to get URL type property", e);
188        }
189    }
190
191    @Override
192    public String getTitle() throws AmetysRepositoryException
193    {
194        try
195        {
196            return getNode().getProperty(PROPERTY_TITLE).getString();
197        }
198        catch (PathNotFoundException e)
199        {
200            return null;
201        }
202        catch (RepositoryException e)
203        {
204            throw new AmetysRepositoryException("Error getting the title property.", e);
205        }
206    }
207
208    @Override
209    public void setTitle(String title) throws AmetysRepositoryException
210    {
211        try
212        {
213            getNode().setProperty(PROPERTY_TITLE, title);
214        }
215        catch (RepositoryException e)
216        {
217            throw new AmetysRepositoryException("Error setting the title property.", e);
218        }
219    }
220
221    @Override
222    public String getContent() throws AmetysRepositoryException
223    {
224        try
225        {
226            return getNode().getProperty(PROPERTY_CONTENT).getString();
227        }
228        catch (PathNotFoundException e)
229        {
230            return null;
231        }
232        catch (RepositoryException e)
233        {
234            throw new AmetysRepositoryException("Error getting the content property.", e);
235        }
236    }
237
238    @Override
239    public void setContent(String content) throws AmetysRepositoryException
240    {
241        try
242        {
243            getNode().setProperty(PROPERTY_CONTENT, content);
244        }
245        catch (RepositoryException e)
246        {
247            throw new AmetysRepositoryException("Error setting the content property.", e);
248        }
249    }
250
251    @Override
252    public String getAlternative() throws AmetysRepositoryException
253    {
254        try
255        {
256            return getNode().getProperty(PROPERTY_URL_ALTERNATIVE).getString();
257        }
258        catch (PathNotFoundException e)
259        {
260            return null;
261        }
262        catch (RepositoryException e)
263        {
264            throw new AmetysRepositoryException("Error getting the alternative property.", e);
265        }
266    }
267
268    @Override
269    public void setAlternative(String alternative) throws AmetysRepositoryException
270    {
271        try
272        {
273            getNode().setProperty(PROPERTY_URL_ALTERNATIVE, alternative);
274        }
275        catch (RepositoryException e)
276        {
277            throw new AmetysRepositoryException("Error setting the alternative property.", e);
278        }
279    }
280
281    @Override
282    public BinaryMetadata getExternalPicture() throws AmetysRepositoryException
283    {
284        return getMetadataHolder().getBinaryMetadata(PROPERTY_PICTURE);
285    }
286
287    @Override
288    public void setExternalPicture(String mimeType, String filename, InputStream stream) throws AmetysRepositoryException
289    {
290        try
291        {
292            removePictureMetas();
293
294            setPictureType("external");
295
296            ModifiableCompositeMetadata meta = getMetadataHolder();
297            ModifiableBinaryMetadata pic = meta.getBinaryMetadata(PROPERTY_PICTURE, true);
298
299            pic.setLastModified(new Date());
300            pic.setInputStream(stream);
301            pic.setMimeType(mimeType);
302            pic.setFilename(filename);
303        }
304        catch (RepositoryException e)
305        {
306            throw new AmetysRepositoryException("Error setting the external picture property.", e);
307        }
308    }
309
310    @Override
311    public String getResourcePictureId() throws AmetysRepositoryException
312    {
313        try
314        {
315            return getNode().getProperty(PROPERTY_PICTURE_ID).getString();
316        }
317        catch (PathNotFoundException e)
318        {
319            return null;
320        }
321        catch (RepositoryException e)
322        {
323            throw new AmetysRepositoryException("Error getting the picture ID property.", e);
324        }
325    }
326
327    @Override
328    public void setResourcePicture(String resourceId) throws AmetysRepositoryException
329    {
330        try
331        {
332            removePictureMetas();
333
334            setPictureType("resource");
335
336            getNode().setProperty(PROPERTY_PICTURE_ID, resourceId);
337        }
338        catch (RepositoryException e)
339        {
340            throw new AmetysRepositoryException("Error setting the alternative property.", e);
341        }
342    }
343
344    @Override
345    public void setNoPicture() throws AmetysRepositoryException
346    {
347        try
348        {
349            setPictureType("");
350
351            removePictureMetas();
352        }
353        catch (RepositoryException e)
354        {
355            throw new AmetysRepositoryException("Error setting the alternative property.", e);
356        }
357    }
358
359    @Override
360    public String getPictureType() throws AmetysRepositoryException
361    {
362        try
363        {
364            return getNode().getProperty(PROPERTY_PICTURE_TYPE).getString();
365        }
366        catch (RepositoryException e)
367        {
368            throw new AmetysRepositoryException("Error getting the type property.", e);
369        }
370    }
371
372    @Override
373    public void setPictureType(String type) throws AmetysRepositoryException
374    {
375        try
376        {
377            getNode().setProperty(PROPERTY_PICTURE_TYPE, type);
378        }
379        catch (RepositoryException e)
380        {
381            throw new AmetysRepositoryException("Error setting the type property.", e);
382        }
383    }
384
385    @Override
386    public String getPictureAlternative() throws AmetysRepositoryException
387    {
388        try
389        {
390            return getNode().getProperty(PROPERTY_PICTURE_ALTERNATIVE).getString();
391        }
392        catch (PathNotFoundException e)
393        {
394            return null;
395        }
396        catch (RepositoryException e)
397        {
398            throw new AmetysRepositoryException("Error getting the alternative property.", e);
399        }
400    }
401
402    @Override
403    public void setPictureAlternative(String alternative) throws AmetysRepositoryException
404    {
405        try
406        {
407            getNode().setProperty(PROPERTY_PICTURE_ALTERNATIVE, alternative);
408        }
409        catch (RepositoryException e)
410        {
411            throw new AmetysRepositoryException("Error setting the alternative property.", e);
412        }
413    }
414
415    @Override
416    public String[] getThemes() throws AmetysRepositoryException
417    {
418        return _getListFromMetadataName(PROPERTY_THEMES);
419    }
420
421    @Override
422    public void setThemes(String[] themes) throws AmetysRepositoryException
423    {
424        _setListWithMetadataName(themes, PROPERTY_THEMES);
425    }
426
427    @Override
428    public void removeTheme(String themeId) throws AmetysRepositoryException
429    {
430        try
431        {
432            String[] themes = getThemes();
433            String[] updatedThemes = ArrayUtils.removeElement(themes, themeId);
434            getNode().setProperty(PROPERTY_THEMES, updatedThemes);
435        }
436        catch (RepositoryException e)
437        {
438            throw new AmetysRepositoryException("Error removing theme of id " + themeId, e);
439        }
440    }
441
442    @Override
443    public UserIdentity[] getGrantedUsers() throws AmetysRepositoryException
444    {
445        try
446        {
447            List<UserIdentity> grantedUsers = new ArrayList<>();
448
449            NodeIterator nodeIt = getGrantedUsersRootNode().getNodes(NODE_NAME_GRANTED_USER);
450            while (nodeIt.hasNext())
451            {
452                Node grantedUser = (Node) nodeIt.next();
453                String login = grantedUser.getProperty(RepositoryConstants.NAMESPACE_PREFIX + ":login").getString();
454                String populationId = grantedUser.getProperty(RepositoryConstants.NAMESPACE_PREFIX + ":population").getString();
455
456                grantedUsers.add(new UserIdentity(login, populationId));
457            }
458            return grantedUsers.toArray(new UserIdentity[grantedUsers.size()]);
459        }
460        catch (RepositoryException e)
461        {
462            throw new AmetysRepositoryException("An error occurred while trying to get granted users.", e);
463        }
464    }
465
466    @Override
467    public void setGrantedUsers(UserIdentity[] grantedUsers) throws AmetysRepositoryException
468    {
469        try
470        {
471            Node rootNode = getGrantedUsersRootNode();
472            rootNode.remove();
473
474            rootNode = getGrantedUsersRootNode();
475            for (UserIdentity grantedUser : grantedUsers)
476            {
477                Node userNode = rootNode.addNode(NODE_NAME_GRANTED_USER, "ametys:user");
478                userNode.setProperty(RepositoryConstants.NAMESPACE_PREFIX + ":login", grantedUser.getLogin());
479                userNode.setProperty(RepositoryConstants.NAMESPACE_PREFIX + ":population", grantedUser.getPopulationId());
480            }
481        }
482        catch (RepositoryException e)
483        {
484            throw new AmetysRepositoryException("An error occurred while setting the granted users.", e);
485        }
486    }
487
488    /**
489     * Get the root node for granted users
490     * 
491     * @return The granted users root node
492     * @throws RepositoryException if an error occurred
493     */
494    protected Node getGrantedUsersRootNode() throws RepositoryException
495    {
496        if (!getNode().hasNode(NODE_NAME_GRANTED_USERS))
497        {
498            getNode().addNode(NODE_NAME_GRANTED_USERS, "ametys:linkGrantedUsers");
499        }
500        return getNode().getNode(NODE_NAME_GRANTED_USERS);
501    }
502
503    @Override
504    public GroupIdentity[] getGrantedGroups() throws AmetysRepositoryException
505    {
506        try
507        {
508            List<GroupIdentity> grantedGroups = new ArrayList<>();
509
510            NodeIterator nodeIt = getGrantedGroupsRootNode().getNodes(NODE_NAME_GRANTED_GROUP);
511            while (nodeIt.hasNext())
512            {
513                Node grantedGroup = (Node) nodeIt.next();
514                String groupId = grantedGroup.getProperty(RepositoryConstants.NAMESPACE_PREFIX + ":groupId").getString();
515                String groupDir = grantedGroup.getProperty(RepositoryConstants.NAMESPACE_PREFIX + ":groupDirectory").getString();
516
517                grantedGroups.add(new GroupIdentity(groupId, groupDir));
518            }
519            return grantedGroups.toArray(new GroupIdentity[grantedGroups.size()]);
520        }
521        catch (RepositoryException e)
522        {
523            throw new AmetysRepositoryException("An error occurred while trying to get granted groups.", e);
524        }
525    }
526
527    @Override
528    public void setGrantedGroups(GroupIdentity[] grantedGroups) throws AmetysRepositoryException
529    {
530        try
531        {
532            Node rootNode = getGrantedGroupsRootNode();
533            rootNode.remove();
534
535            rootNode = getGrantedGroupsRootNode();
536            for (GroupIdentity grantedGroup : grantedGroups)
537            {
538                Node groupNode = rootNode.addNode(NODE_NAME_GRANTED_GROUP, "ametys:group");
539                groupNode.setProperty(RepositoryConstants.NAMESPACE_PREFIX + ":groupId", grantedGroup.getId());
540                groupNode.setProperty(RepositoryConstants.NAMESPACE_PREFIX + ":groupDirectory", grantedGroup.getDirectoryId());
541            }
542        }
543        catch (RepositoryException e)
544        {
545            throw new AmetysRepositoryException("An error occurred while setting the granted groups.", e);
546        }
547    }
548
549    /**
550     * Get the root node for granted users
551     * 
552     * @return The granted users root node
553     * @throws RepositoryException if an error occurred
554     */
555    protected Node getGrantedGroupsRootNode() throws RepositoryException
556    {
557        if (!getNode().hasNode(NODE_NAME_GRANTED_GROUPS))
558        {
559            getNode().addNode(NODE_NAME_GRANTED_GROUPS, "ametys:linkGrantedGroups");
560        }
561        return getNode().getNode(NODE_NAME_GRANTED_GROUPS);
562    }
563
564    @Override
565    public boolean isAllowedAnyUser() throws AmetysRepositoryException
566    {
567        Node node = getNode();
568        try
569        {
570            return node.hasProperty(PROPERTY_GRANT_ANY_USER) ? getNode().getProperty(PROPERTY_GRANT_ANY_USER).getBoolean() : false;
571        }
572        catch (RepositoryException e)
573        {
574            throw new AmetysRepositoryException("An error occurred while trying to get the 'grant-any-user' property.", e);
575        }
576    }
577
578    @Override
579    public void setGrantAnyUser(boolean grantAnyUser) throws AmetysRepositoryException
580    {
581        try
582        {
583            getNode().setProperty(PROPERTY_GRANT_ANY_USER, grantAnyUser);
584        }
585        catch (RepositoryException e)
586        {
587            throw new AmetysRepositoryException("An error occurred while trying to set the 'grant-any-user' property.", e);
588        }
589    }
590
591    @Override
592    public Site getSite() throws AmetysRepositoryException
593    {
594        AmetysObject parent = getParent();
595        while (parent != null)
596        {
597            if (parent instanceof Site)
598            {
599                return (Site) parent;
600            }
601            parent = parent.getParent();
602        }
603
604        return null;
605    }
606
607    @Override
608    public String getSiteName() throws AmetysRepositoryException
609    {
610        return getSite().getName();
611    }
612
613    /**
614     * Get the theme language.
615     * 
616     * @return the theme language.
617     */
618    public String getLanguage()
619    {
620        return getParent().getParent().getName();
621    }
622
623    /**
624     * Remove all picture metas (picture ID and picture binary).
625     * 
626     * @throws RepositoryException if an error occurs.
627     */
628    protected void removePictureMetas() throws RepositoryException
629    {
630        getNode().setProperty(PROPERTY_PICTURE_ID, "");
631
632        ModifiableCompositeMetadata meta = getMetadataHolder();
633        if (meta.hasMetadata(PROPERTY_PICTURE))
634        {
635            meta.removeMetadata(PROPERTY_PICTURE);
636        }
637    }
638
639    @Override
640    public void orderBefore(AmetysObject siblingObject) throws AmetysRepositoryException
641    {
642        if (siblingObject instanceof DefaultLink)
643        {
644            DefaultLink sibling = (DefaultLink) siblingObject;
645            sibling.getPath();
646            Node node = getNode();
647            String siblingPath = "";
648            try
649            {
650                siblingPath = sibling.getNode().getPath();
651                if (siblingPath.contains("/"))
652                {
653                    siblingPath = StringUtils.substringAfterLast(siblingPath, "/");
654                }
655                String path = node.getPath();
656                if (path.contains("/"))
657                {
658                    path = StringUtils.substringAfterLast(path, "/");
659                }
660                node.getParent().orderBefore(path, siblingPath);
661            }
662            catch (RepositoryException e)
663            {
664                throw new AmetysRepositoryException(String.format("Unable to order link '%s' before link '%s'", this, siblingPath), e);
665            }
666        }
667        else
668        {
669            throw new AmetysRepositoryException("A link can only be moved before another link.");
670        }
671    }
672
673    @Override
674    public void moveTo(AmetysObject newParent, boolean renameIfExist) throws AmetysRepositoryException, RepositoryIntegrityViolationException
675    {
676        if (getParent().equals(newParent))
677        {
678            try
679            {
680                // Just order current node to the end.
681                Node node = getNode();
682                String path = node.getPath();
683                if (path.contains("/"))
684                {
685                    path = StringUtils.substringAfterLast(path, "/");
686                }
687                node.getParent().orderBefore(path, null);
688            }
689            catch (RepositoryException e)
690            {
691                throw new AmetysRepositoryException(String.format("Unable to move link '%s' outside the root link node.", this), e);
692            }
693        }
694        else
695        {
696            throw new AmetysRepositoryException("A link can only be moved before another link.");
697        }
698    }
699
700    @Override
701    public boolean canMoveTo(AmetysObject newParent) throws AmetysRepositoryException
702    {
703        return getParent().equals(newParent);
704    }
705
706    /**
707     * Retrieves the list of values corresponding to the metadata name passed as
708     * parameter
709     * 
710     * @param metadataName the name of the metadata to retrieve
711     * @return the list corresponding to the metadata name
712     */
713    private String[] _getListFromMetadataName(String metadataName)
714    {
715        try
716        {
717            if (getNode().hasProperty(metadataName))
718            {
719                Value[] values = getNode().getProperty(metadataName).getValues();
720
721                String[] list = new String[values.length];
722
723                for (int i = 0; i < values.length; i++)
724                {
725                    list[i] = values[i].getString();
726                }
727
728                return list;
729            }
730            else
731            {
732                return new String[0];
733            }
734        }
735        catch (RepositoryException e)
736        {
737            throw new AmetysRepositoryException("An error occurred while trying to get the property '" + metadataName + "'.", e);
738        }
739    }
740
741    /**
742     * Sets the list of values to the node corresponding to the metadata name
743     * passed as a parameter
744     * 
745     * @param list the list of value to be set
746     * @param metadataName the name of the metadata
747     */
748    private void _setListWithMetadataName(String[] list, String metadataName)
749    {
750        try
751        {
752            getNode().setProperty(metadataName, list);
753        }
754        catch (RepositoryException e)
755        {
756            throw new AmetysRepositoryException("An error occurred while trying to set the property '" + metadataName + "'.", e);
757        }
758    }
759
760    @Override
761    public String getDynamicInformationProvider() throws AmetysRepositoryException
762    {
763        try
764        {
765            return getNode().getProperty(PROPERTY_DYNAMIC_INFO_PROVIDER).getString();
766        }
767        catch (PathNotFoundException e)
768        {
769            return null;
770        }
771        catch (RepositoryException e)
772        {
773            throw new AmetysRepositoryException("Error getting the URL property.", e);
774        }
775    }
776
777    @Override
778    public void setDynamicInformationProvider(String providerId) throws AmetysRepositoryException
779    {
780        try
781        {
782            getNode().setProperty(PROPERTY_DYNAMIC_INFO_PROVIDER, providerId);
783        }
784        catch (RepositoryException e)
785        {
786            throw new AmetysRepositoryException("Error setting the URL property.", e);
787        }
788    }
789
790}