001/*
002 *  Copyright 2011 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 */
016
017package org.ametys.plugins.repository.dom;
018
019import java.util.HashMap;
020import java.util.Iterator;
021import java.util.Map;
022
023import org.w3c.dom.Element;
024import org.w3c.dom.Node;
025
026import org.ametys.core.util.dom.AbstractWrappingAmetysElement;
027import org.ametys.core.util.dom.AmetysAttribute;
028import org.ametys.plugins.repository.AmetysObject;
029import org.ametys.plugins.repository.AmetysObjectIterable;
030import org.ametys.plugins.repository.TraversableAmetysObject;
031import org.ametys.plugins.repository.data.ametysobject.DataAwareAmetysObject;
032import org.ametys.plugins.repository.data.ametysobject.ModelLessDataAwareAmetysObject;
033import org.ametys.plugins.repository.data.holder.DataHolder;
034import org.ametys.plugins.repository.data.holder.ModelAwareDataHolder;
035import org.ametys.plugins.repository.data.holder.ModelLessDataHolder;
036import org.ametys.plugins.repository.metadata.CompositeMetadata;
037import org.ametys.plugins.repository.metadata.CompositeMetadata.MetadataType;
038import org.ametys.plugins.repository.metadata.MetadataAwareAmetysObject;
039import org.ametys.runtime.model.type.ElementType;
040import org.ametys.runtime.model.type.ModelItemType;
041
042/**
043 * Implementation of {@link Element} wrapping an {@link AmetysObject}.<br>
044 * Only methods useful for XPath processing are implemented.
045 * @param <A> the actual type of the wrapped {@link AmetysObject}.
046 */
047public class AmetysObjectElement<A extends AmetysObject> extends AbstractWrappingAmetysElement<A>
048{
049    /**
050     * Constructor.
051     * @param object the underlying {@link AmetysObject}.
052     */
053    public AmetysObjectElement(A object)
054    {
055        this(object, null);
056    }
057    
058    /**
059     * Constructor.
060     * @param object the underlying {@link AmetysObject}.
061     * @param parent the parent {@link Element}.
062     */
063    public AmetysObjectElement(A object, AmetysObjectElement<? extends TraversableAmetysObject> parent)
064    {
065        super(object, parent);
066    }
067
068    @Override
069    public String getTagName()
070    {
071        return _object.getName();
072    }
073    
074    /**
075     * This implementation returns all non-composite metadata.
076     */
077    @Override
078    protected Map<String, AmetysAttribute> _lookupAttributes()
079    {
080        Map<String, AmetysAttribute> result = new HashMap<>();
081        
082        if (_object instanceof DataAwareAmetysObject)
083        {
084            DataHolder dataHolder = ((ModelLessDataAwareAmetysObject) _object).getDataHolder();
085            
086            for (String name : dataHolder.getDataNames())
087            {
088                ModelItemType type = _getDataType(dataHolder, name);
089                if (type instanceof ElementType && ((ElementType) type).isSimple() && !_isDataMultiple(dataHolder, name))
090                {
091                    Object value = _getValue(dataHolder, name);
092                    @SuppressWarnings("unchecked")
093                    String valueAsString = ((ElementType) type).toString(value);
094                    result.put(name, new AmetysAttribute(name, name, null, valueAsString, this));
095                }
096            }
097        }
098        else if (_object instanceof MetadataAwareAmetysObject)
099        {
100            CompositeMetadata metadata = ((MetadataAwareAmetysObject) _object).getMetadataHolder();
101            
102            String[] names = metadata.getMetadataNames();
103            
104            for (String name : names)
105            {
106                MetadataType type = metadata.getType(name);
107                if (type != MetadataType.COMPOSITE && type != MetadataType.USER && type != MetadataType.BINARY && type != MetadataType.RICHTEXT && type != MetadataType.OBJECT_COLLECTION && !metadata.isMultiple(name))
108                {
109                    String value = metadata.getString(name);
110                    result.put(name, new AmetysAttribute(name, name, null, value, this));
111                }
112            }
113        }
114        
115        return result;
116    }
117    
118    private ModelItemType _getDataType(DataHolder dataHolder, String dataName)
119    {
120        return dataHolder instanceof ModelAwareDataHolder ? ((ModelAwareDataHolder) dataHolder).getType(dataName) : ((ModelLessDataHolder) dataHolder).getType(dataName);
121    }
122    
123    private boolean _isDataMultiple(DataHolder dataHolder, String dataName)
124    {
125        return dataHolder instanceof ModelAwareDataHolder ? ((ModelAwareDataHolder) dataHolder).isMultiple(dataName) : ((ModelLessDataHolder) dataHolder).isMultiple(dataName);
126    }
127    
128    private <T> T _getValue(DataHolder dataHolder, String dataName)
129    {
130        return dataHolder instanceof ModelAwareDataHolder ? ((ModelAwareDataHolder) dataHolder).getValue(dataName) : ((ModelLessDataHolder) dataHolder).getValue(dataName);
131    }
132    
133    @Override
134    public boolean hasChildNodes()
135    {
136        if (_object instanceof TraversableAmetysObject)
137        {
138            AmetysObjectIterable<AmetysObject> children = ((TraversableAmetysObject) _object).getChildren();
139            
140            return children.iterator().hasNext();
141        }
142        
143        return false;
144    }
145    
146    @SuppressWarnings("unchecked")
147    @Override
148    public Node getFirstChild()
149    {
150        if (_object instanceof TraversableAmetysObject)
151        {
152            AmetysObjectIterable<AmetysObject> children = ((TraversableAmetysObject) _object).getChildren();
153            Iterator<AmetysObject> it = children.iterator();
154            
155            if (!it.hasNext())
156            {
157                return null;
158            }
159            
160            return new AmetysObjectElement<>(it.next(), (AmetysObjectElement<TraversableAmetysObject>) this);
161        }
162        
163        return null;
164    }
165    
166    @SuppressWarnings("unchecked")
167    @Override
168    public Node getNextSibling()
169    {
170        if (_parent == null)
171        {
172            return null;
173        }
174        
175        TraversableAmetysObject parent = (TraversableAmetysObject) ((AbstractWrappingAmetysElement) _parent).getWrappedObject();
176        
177        AmetysObjectIterable<AmetysObject> children = parent.getChildren();
178        
179        boolean isNext = false;
180        AmetysObject nextSibling = null;
181        Iterator<AmetysObject> it = children.iterator();
182        
183        while (nextSibling == null && it.hasNext())
184        {
185            AmetysObject child = it.next();
186            
187            if (isNext)
188            {
189                nextSibling = child;
190            }
191            else if (_object.getId().equals(child.getId()))
192            {
193                isNext = true;
194            }
195        }
196        
197        return nextSibling == null ? null : new AmetysObjectElement<>(nextSibling, (AmetysObjectElement< ? extends TraversableAmetysObject>) _parent);
198    }
199}