All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scriptella.configuration.ContentEl Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2006-2012 The Scriptella Project Team.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package scriptella.configuration;

import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.Text;
import scriptella.spi.Resource;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;


/**
 * TODO: Add documentation
 *
 * @author Fyodor Kupolov
 * @version 1.0
 */
public class ContentEl extends XmlConfigurableBase implements Resource {
    /**
     * Max length of string resource to concat with the previous one.
     * This limitation is necessary to avoid concatenation of large text blocks, because in this
     * case too much memory is used.
     */
    private static final int MAX_CONCAT_RESOURCE_LENGTH = 1024 * 128; //128Kb
    private List content = new ArrayList();
    /**
     * Null-Object to use instead of null if necessary
     */
    public static final Resource NULL_CONTENT = new StringResource("", "Empty Content");

    public ContentEl() {
    }

    public ContentEl(XmlElement element) {
        configure(element);
    }

    public Reader open() throws IOException {
        if (content.isEmpty()) {
            return NULL_CONTENT.open();
        }
        //If content consists of only one resource - open it
        if (content.size() == 1) {
            return content.get(0).open();
        }
        //Otherwise create a multipart reader.
        return new BufferedReader(new MultipartReader());
    }

    public void configure(final XmlElement element) {
        for (Node node = element.getElement().getFirstChild(); node != null; node = node.getNextSibling()) {
            append(asResource(element, node));
        }
    }


    /**
     * Creates a resource using content from the specified node.
     * 

If node is not textual content or not include element, the content is skipped and null is returned. * * @param parentElement parent element of this node. * @param node node to get content from. * @return parsed resource or null. */ static Resource asResource(final XmlElement parentElement, final Node node) { if (node == null) { return null; } if (node instanceof Text) { return new StringResource(((Text) node).getData()); } else if (node instanceof Element && "include".equals(node.getNodeName())) { return new IncludeEl(new XmlElement((Element) node, parentElement)); } return null; } /** * Merges this content with specified one and returns this element. * * @param contentEl content to merge with. * @return this instance with merged content. */ final ContentEl merge(final ContentEl contentEl) { content.addAll(contentEl.content); return this; } /** * Appends a resource to this content. * * @param resource resource to append. Nulls are ignored. */ final void append(final Resource resource) { if (resource != null) { //If string resource and we already have content if (resource instanceof StringResource && !content.isEmpty()) { final int lastIndex = content.size() - 1; Resource last = content.get(lastIndex); if (last instanceof StringResource) { //If last resource is also a string resource //Concat them and produce a new resource if new size does not exceed the memory limit StringResource nextRes = (StringResource) resource; StringResource prevRes = (StringResource) last; if (prevRes.getString().length() + nextRes.getString().length() < MAX_CONCAT_RESOURCE_LENGTH) { content.set(lastIndex, new StringResource(prevRes.getString() + nextRes.getString())); return; } } } content.add(resource); } } /** * Returns resources represented by this content. * * @return list of resources represented by this content. */ public List getResources() { return content; } @Override public String toString() { Location loc = getLocation(); return loc != null ? loc.toString() : ("ContentEl{" + "content=" + content + '}'); } class MultipartReader extends Reader { private int pos = 0; private Reader current; private int blocksCount = content.size(); public int read(final char cbuf[], final int off, final int len) throws IOException { if ((pos < 0) || ((pos >= blocksCount) && (current == null))) { return -1; } int l = len; int o = off; while (l > 0) { if (current == null) { if (pos < blocksCount) { current = content.get(pos).open(); pos++; } else { return ((len - l) <= 0) ? (-1) : (len - l); } } else { final int r = current.read(cbuf, o, l); if (r <= 0) { current.close(); current = null; } else if (r <= l) { l -= r; o += r; } } } return len - l; } public void close() throws IOException { if (current != null) { current.close(); current = null; } pos = -1; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy