001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.markup;
018
019import java.io.IOException;
020import java.util.ArrayList;
021import java.util.Collections;
022import java.util.Iterator;
023import java.util.List;
024
025import org.apache.wicket.util.lang.Args;
026import org.apache.wicket.util.resource.ResourceStreamNotFoundException;
027import org.apache.wicket.util.string.AppendingStringBuffer;
028
029
030/**
031 * The content of a markup file, consisting of a list of markup elements.
032 * 
033 * @see MarkupResourceStream
034 * @see MarkupElement
035 * @see ComponentTag
036 * @see RawMarkup
037 * 
038 * @author Juergen Donnerstag
039 */
040public class Markup extends AbstractMarkupFragment
041{
042        /** Placeholder that indicates no markup */
043        public static final Markup NO_MARKUP = new Markup();
044
045        /** The list of markup elements */
046        private/* final */List<MarkupElement> markupElements;
047
048        /** The associated markup file */
049        private final MarkupResourceStream markupResourceStream;
050
051        /**
052         * Take the markup string, parse it and return the Markup (list of MarkupElements).
053         * <p>
054         * Limitation: Please note that MarkupFactory is NOT used and thus no caching is used (which
055         * doesn't matter for Strings anyway), but what might matter is that your own MarkupFilters are
056         * not applied, which you might have registered with MarkupFactory.
057         * 
058         * @param markup
059         *      the string to use as markup
060         * @return Markup The parsed markup
061         */
062        public static Markup of(final String markup)
063        {
064                return of(markup, MarkupParser.WICKET);
065        }
066
067        /**
068         * Take the markup string, parse it and return the Markup (list of MarkupElements).
069         * <p>
070         * Limitation: Please note that MarkupFactory is NOT used and thus no caching is used (which
071         * doesn't matter for Strings anyway), but what might matter is that your own MarkupFilters are
072         * not applied, which you might have registered with MarkupFactory.
073         *
074         * @param markup
075         *      the string to use as markup
076         * @param wicketNamespace
077         *      the namespace for Wicket elements and attributes
078         * @return Markup The parsed markup
079         */
080        public static Markup of(final String markup, String wicketNamespace)
081        {
082                try
083                {
084                        MarkupParser markupParser = new MarkupParser(markup);
085                        markupParser.setWicketNamespace(wicketNamespace);
086                        return markupParser.parse();
087                }
088                catch (IOException ex)
089                {
090                        throw new RuntimeException(ex);
091                }
092                catch (ResourceStreamNotFoundException ex)
093                {
094                        throw new RuntimeException(ex);
095                }
096        }
097
098        /**
099         * Private Constructor for NO_MARKUP only
100         */
101        private Markup()
102        {
103                markupResourceStream = null;
104        }
105
106        /**
107         * Constructor
108         * 
109         * @param markupResourceStream
110         *            The associated Markup
111         */
112        public Markup(final MarkupResourceStream markupResourceStream)
113        {
114                Args.notNull(markupResourceStream, "markupResourceStream");
115
116                this.markupResourceStream = markupResourceStream;
117                markupElements = new ArrayList<>();
118        }
119
120        @Override
121        public final MarkupElement get(final int index)
122        {
123                return markupElements.get(index);
124        }
125
126        @Override
127        public final MarkupResourceStream getMarkupResourceStream()
128        {
129                return markupResourceStream;
130        }
131
132        /**
133         * 
134         * @param index
135         * @param elem
136         */
137        public final void replace(final int index, final MarkupElement elem)
138        {
139                Args.notNull(elem, "elem");
140
141                if ((index < 0) || (index >= size()))
142                {
143                        throw new IndexOutOfBoundsException("'index' must be smaller than size(). Index:" +
144                                index + "; size:" + size());
145                }
146
147                markupElements.set(index, elem);
148        }
149
150        /**
151         * 
152         * @return The fixed location as a string, e.g. the file name or the URL. Return null to avoid
153         *         caching the markup.
154         */
155        public String locationAsString()
156        {
157                return markupResourceStream.locationAsString();
158        }
159
160        @Override
161        public final int size()
162        {
163                return markupElements.size();
164        }
165
166        /**
167         * Add a MarkupElement
168         * 
169         * @param markupElement
170         */
171        final public void addMarkupElement(final MarkupElement markupElement)
172        {
173                markupElements.add(markupElement);
174        }
175
176        /**
177         * Add a MarkupElement
178         * 
179         * @param pos
180         * @param markupElement
181         */
182        final public void addMarkupElement(final int pos, final MarkupElement markupElement)
183        {
184                markupElements.add(pos, markupElement);
185        }
186
187        /**
188         * Make all tags immutable and the list of elements unmodifiable.
189         */
190        final public void makeImmutable()
191        {
192                for (MarkupElement markupElement : markupElements)
193                {
194                        if (markupElement instanceof ComponentTag)
195                        {
196                                // Make the tag immutable
197                                ((ComponentTag)markupElement).makeImmutable();
198                        }
199                }
200
201                markupElements = Collections.unmodifiableList(markupElements);
202        }
203
204        @Override
205        public final IMarkupFragment find(final String id)
206        {
207                return find(id, 0);
208        }
209
210        @Override
211        public final String toString()
212        {
213                return toString(false);
214        }
215
216        /**
217         * @param markupOnly
218         *            True, if only the markup shall be returned
219         * @return String
220         */
221        @Override
222        public final String toString(final boolean markupOnly)
223        {
224                final AppendingStringBuffer buf = new AppendingStringBuffer(400);
225
226                if (markupOnly == false)
227                {
228                        if (markupResourceStream != null)
229                        {
230                                buf.append(markupResourceStream.toString());
231                        }
232                        else
233                        {
234                                buf.append("null MarkupResouceStream");
235                        }
236                        buf.append("\n");
237                }
238
239                if (markupElements != null)
240                {
241                        for (MarkupElement markupElement : markupElements)
242                        {
243                                buf.append(markupElement);
244                        }
245                }
246
247                return buf.toString();
248        }
249
250        /**
251         * @see java.lang.Iterable#iterator()
252         */
253        @Override
254        public final Iterator<MarkupElement> iterator()
255        {
256                return markupElements.iterator();
257        }
258
259        /**
260         * @param startIndex
261         * @param size
262         * @return Iterator
263         */
264        public final Iterator<MarkupElement> iterator(int startIndex, int size)
265        {
266                return markupElements.subList(startIndex, startIndex + size).iterator();
267        }
268}