001/*
002 *   Copyright (C) 2005 Christian Schulte <cs@schulte.it>
003 *   All rights reserved.
004 *
005 *   Redistribution and use in source and binary forms, with or without
006 *   modification, are permitted provided that the following conditions
007 *   are met:
008 *
009 *     o Redistributions of source code must retain the above copyright
010 *       notice, this list of conditions and the following disclaimer.
011 *
012 *     o Redistributions in binary form must reproduce the above copyright
013 *       notice, this list of conditions and the following disclaimer in
014 *       the documentation and/or other materials provided with the
015 *       distribution.
016 *
017 *   THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
018 *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
019 *   AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
020 *   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
021 *   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
022 *   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
023 *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
024 *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025 *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
026 *   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027 *
028 *   $JOMC: ModelValidationReport.java 5269 2016-08-11 23:38:09Z schulte $
029 *
030 */
031package org.jomc.modlet;
032
033import java.io.Serializable;
034import java.util.ArrayList;
035import java.util.Collections;
036import java.util.List;
037import java.util.concurrent.CopyOnWriteArrayList;
038import java.util.logging.Level;
039import javax.xml.bind.JAXBElement;
040
041/**
042 * {@code Model} validation report.
043 *
044 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
045 * @version $JOMC: ModelValidationReport.java 5269 2016-08-11 23:38:09Z schulte $
046 */
047public class ModelValidationReport implements Serializable
048{
049
050    /**
051     * Report detail.
052     */
053    public static class Detail implements Serializable
054    {
055
056        /**
057         * Serial version UID for backwards compatibility with 1.0.x object streams.
058         */
059        private static final long serialVersionUID = -2466230076806042116L;
060
061        /**
062         * The detail identifier.
063         *
064         * @serial
065         */
066        private final String identifier;
067
068        /**
069         * The detail level.
070         *
071         * @serial
072         */
073        private final Level level;
074
075        /**
076         * The detail message.
077         *
078         * @serial
079         */
080        private final String message;
081
082        /**
083         * The JAXB element this detail is associated with.
084         *
085         * @serial
086         */
087        private final JAXBElement<?> element;
088
089        /**
090         * Creates a new {@code Detail} taking an identifier, a level, a message and an element.
091         *
092         * @param identifier The detail identifier.
093         * @param level The detail level.
094         * @param message The detail message.
095         * @param element The detail element.
096         */
097        public Detail( final String identifier, final Level level, final String message, final JAXBElement<?> element )
098        {
099            this.identifier = identifier;
100            this.level = level;
101            this.message = message;
102            this.element = element;
103        }
104
105        /**
106         * Gets the identifier of this detail.
107         *
108         * @return The identifier of this detail or {@code null}.
109         */
110        public String getIdentifier()
111        {
112            return this.identifier;
113        }
114
115        /**
116         * Gets the level of this detail.
117         *
118         * @return The level of this detail or {@code null}.
119         */
120        public Level getLevel()
121        {
122            return this.level;
123        }
124
125        /**
126         * Gets the message of this detail.
127         *
128         * @return The message of this detail or {@code null}.
129         */
130        public String getMessage()
131        {
132            return this.message;
133        }
134
135        /**
136         * Gets the JAXB element of this detail.
137         *
138         * @return The JAXB element of this detail or {@code null}.
139         */
140        public JAXBElement<?> getElement()
141        {
142            return this.element;
143        }
144
145        /**
146         * Creates and returns a string representation of the object.
147         *
148         * @return A string representation of the object.
149         */
150        private String toStringInternal()
151        {
152            return new StringBuilder( 200 ).append( '{' ).
153                append( "identifier=" ).append( this.getIdentifier() ).
154                append( ", level=" ).append( this.getLevel().getLocalizedName() ).
155                append( ", message=" ).append( this.getMessage() ).
156                append( ", element=" ).append( this.getElement() ).append( '}' ).toString();
157
158        }
159
160        /**
161         * Creates and returns a string representation of the object.
162         *
163         * @return A string representation of the object.
164         */
165        @Override
166        public String toString()
167        {
168            return super.toString() + this.toStringInternal();
169        }
170
171    }
172
173    /**
174     * Serial version UID for backwards compatibility with 1.0.x object streams.
175     */
176    private static final long serialVersionUID = 6688024709865043122L;
177
178    /**
179     * Details of the instance.
180     *
181     * @serial
182     */
183    private final List<Detail> details = new CopyOnWriteArrayList<Detail>();
184
185    /**
186     * Creates a new {@code ModelValidationReport} instance.
187     */
188    public ModelValidationReport()
189    {
190        super();
191    }
192
193    /**
194     * Gets all details of the instance.
195     * <p>
196     * This accessor method returns a reference to the live list, not a snapshot. Therefore any modification you make
197     * to the returned list will be present inside the object. This is why there is no {@code set} method for the
198     * details property.
199     * </p>
200     *
201     * @return All details of the instance.
202     */
203    public List<Detail> getDetails()
204    {
205        return this.details;
206    }
207
208    /**
209     * Gets all details of the instance matching a given identifier.
210     *
211     * @param identifier The identifier of the details to return or {@code null}.
212     *
213     * @return An unmodifiable list containing all details of the instance matching {@code identifier}.
214     */
215    public List<Detail> getDetails( final String identifier )
216    {
217        final List<Detail> list = new ArrayList<Detail>( this.getDetails().size() );
218
219        for ( final Detail detail : this.getDetails() )
220        {
221            if ( identifier == null && detail.getIdentifier() == null )
222            {
223                list.add( detail );
224            }
225            if ( identifier != null && identifier.equals( detail.getIdentifier() ) )
226            {
227                list.add( detail );
228            }
229        }
230
231        return Collections.unmodifiableList( list );
232    }
233
234    /**
235     * Gets a flag indicating model validity.
236     *
237     * @return {@code true}, if all details are set to a level lower or equal to {@code WARNING}; {@code false}, if at
238     * least one detail is set to a level higher than {@code WARNING}.
239     *
240     * @see #getDetails()
241     */
242    public boolean isModelValid()
243    {
244        for ( final Detail detail : this.getDetails() )
245        {
246            if ( detail.getLevel() != null && detail.getLevel().intValue() > Level.WARNING.intValue() )
247            {
248                return false;
249            }
250        }
251
252        return true;
253    }
254
255}