xmlconverter.controller.logic.GetFileCount.java Source code

Java tutorial

Introduction

Here is the source code for xmlconverter.controller.logic.GetFileCount.java

Source

/*
 *    Copyright (C) 2016  Artiom Blinvoas
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package xmlconverter.controller.logic;

import java.io.File;
import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.DirectoryFileFilter;
import org.apache.commons.io.filefilter.FalseFileFilter;
import org.apache.log4j.Logger;
import xmlconverter.data.MasterBean;
import xmlconverter.items.CreateGraphicsNode;
import xmlconverter.items.site.Site;

/**
 * This class is responsible for creation of XML file in a directories.
 * getFile() method passes absolute path of defined directory to writeFile()
 * method.
 *
 * writeFile() creates actual XML file in the directory. updateAnlage() method
 * is responsible for updating <code>Anlagenbaum.xml</code> file depending on
 * directories been created.
 *
 * Example: If new directory has been added/created it will detect what new
 * folder has not yet been added to the file. If no directory is modified it
 * will not update <code>Anlagebaum.xml</code> but it will check for changes.
 *
 * filterList() acts like a filter for input.
 */
public class GetFileCount {

    //Some file filters
    private final FileFilter directoryFilter = new FileFilter() {
        @Override
        public boolean accept(File file) {
            return file.isDirectory();
        }
    };

    private int flag;
    private final int maNumber;
    private final File home;
    private String slash = File.separator;
    private static Logger log = Logger.getLogger(GetFileCount.class.getName());
    private MasterBean bean;

    /**
     * Use this constructor for all methods that are in this class.
     *
     * @param bean
     */
    public GetFileCount(MasterBean bean) {
        this.home = bean.getEnvBean().getHome();
        this.maNumber = bean.getUserInputBean().getIndexMa();
        this.flag = bean.getUserInputBean().getFlag();
        this.bean = bean;
    }

    /**
     * Creates Document so that XML file can be filled with information. Here
     * where it all begins. Those if statements will first check if files[] is
     * not empty then loop trough files[] and get path of every directory. In
     * the process it passes list of child files/directories paths ("depending
     * on the filter that is used") of a parent file to method called
     * writeFile(). Before that happens it checks if here are any duplicate
     * files that have been handed to the method(It should not happen). After
     * this operation is done it call itself again. Till every folder has been
     * visited.
     *
     * @param site
     * @throws javax.xml.transform.TransformerException
     * @throws javax.xml.parsers.ParserConfigurationException
     * @throws org.xml.sax.SAXException
     * @throws java.io.IOException
     */
    public void writeFile(Site site)
            throws TransformerException, DOMException, ParserConfigurationException, IOException, SAXException {
        ArrayList<String> detectionList = site.getSiteAsArrayList();
        File startPath = bean.getEnvBean().getSiteDir();

        Collection<File> startFiles = FileUtils.listFilesAndDirs(startPath, FalseFileFilter.FALSE,
                DirectoryFileFilter.DIRECTORY);
        File[] startFilesSorted = startFiles.toArray(new File[startFiles.size()]);
        Arrays.sort(startFilesSorted);

        for (File path : startFilesSorted) {
            //Start of the file
            CreateGraphicsNode createGraphicsNode = new CreateGraphicsNode();

            DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder docBuilder = docFactory.newDocumentBuilder();

            Document doc = docBuilder.newDocument();

            Element root = doc.createElement("GraphicsContainerNode");
            Element startMelder = doc.createElement("GraphicsNode");
            Element endMelder = doc.createElement("GraphicsNode");
            doc.appendChild(root);

            //This method also does update. It is actually enables other method to 
            //do update if flag is set to 1
            File[] pathFiles = path.listFiles(directoryFilter);
            Arrays.sort(pathFiles);

            for (File desc : pathFiles) {
                root.appendChild(createGraphicsNode.getGraphicsNode(doc, desc, home));
            }

            if (path.getName().contains("Automatische Gruppe") || path.getName().contains("Manuelle Gruppe")) {
                ArrayList<String> detectionObjects = new ArrayList<>();
                String pattern = path.getName().trim();
                int index = detectionList.indexOf(pattern);

                while (detectionList.get(index + 1).contains("Manual")
                        || detectionList.get(index + 1).contains("Automatic")) {
                    detectionObjects.add(detectionList.get(index + 1));
                    detectionObjects.add(detectionList.get(index + 2));
                    index += 2;
                }
                //This is more efficient way to retrieve information! o guess that helped. 
                if (!detectionObjects.isEmpty()) {
                    int end = path.getName().indexOf("_");
                    String mg = path.getName().substring(0, end);
                    String start;
                    String ending;
                    if ((maNumber + 1) >= 10) {
                        start = (maNumber + 1) + "/11*" + mg + "             ..";
                        ending = (maNumber + 1) + "/11*" + mg + "             00";
                    } else {
                        start = "0" + (maNumber + 1) + "/11*" + mg + "             ..";
                        ending = "0" + (maNumber + 1) + "/11*" + mg + "             00";
                    }
                    startMelder.setAttribute("id", start);
                    startMelder.setAttribute("name", start);
                    root.appendChild(startMelder);
                    for (int i = 0; i < detectionObjects.size(); i += 2) {
                        root.appendChild(createGraphicsNode.getMelderGruppeNode(doc, detectionObjects.get(i),
                                path.getName(), maNumber, detectionObjects.get(i + 1)));
                    }
                    endMelder.setAttribute("id", ending);
                    endMelder.setAttribute("name", ending);
                    root.appendChild(endMelder);
                }
            }

            String formatedFileName = path.getAbsolutePath().replace("", "ae").replace("", "ss")
                    .replace("", "ue").replace("", "oe");
            String formatedName = path.getName().replace("", "ae").replace("", "ss").replace("", "ue")
                    .replace("", "oe");

            File toCheck;
            if (path.getAbsolutePath().endsWith(".xml")) {
                toCheck = path;
            } else {
                toCheck = new File(formatedFileName + slash + formatedName + ".xml");
            }

            //End Of the File
            //Flag 0 - Default 1 - Override 2 - Update
            if (flag != 2) {
                writeDocument(doc, path);
            }
            if (flag == 2) {
                if (toCheck.exists()) {
                    //If it existas that measns it could need some updating
                    updateSite(doc, toCheck);
                } else {
                    //if not then file can be created and doesnt need to be updated.
                    writeDocument(doc, path);
                }
            }
        }
    }

    /**
     * This method is/are going to update the site information. The statements
     * are based on flags that are passed. This method should detect if files
     * content has changed and also update thous changed if node count has
     * changed.
     *
     * @param path
     * @param pathXml
     * @throws DOMException
     * @throws IOException
     * @throws ParserConfigurationException
     * @throws SAXException
     * @throws TransformerException
     */
    private void updateSite(Document newDoc, File pathXml)
            throws TransformerException, DOMException, ParserConfigurationException, IOException, SAXException {
        //System.out.println("I updated: " + pathXml.getName());
        DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
        Document oldDoc = docBuilder.parse(pathXml);

        //Old root & NodeList
        Node root = oldDoc.getFirstChild();
        NodeList staff = root.getChildNodes();
        ArrayList<Node> oldNodes = new ArrayList<>();

        for (int i = 0; i < staff.getLength(); i++) {
            oldNodes.add(staff.item(i));
        }

        //New root & NodeList
        Node rootNew = newDoc.getFirstChild();
        NodeList staffNew = rootNew.getChildNodes();
        ArrayList<Node> newNodes = new ArrayList<>();

        for (int i = 0; i < staffNew.getLength(); i++) {
            newNodes.add(staffNew.item(i));
        }
        //        * All extra nodes will be removed
        //        * All not maching "id's" will be replaced
        if (oldNodes.size() > newNodes.size()) {
            for (int i = 0; i < oldNodes.size(); i++) {
                if (i >= newNodes.size()) {
                    root.removeChild(oldNodes.get(i));//remove extra old nodes
                } else if (!oldNodes.get(i).getAttributes().getNamedItem("id").getNodeValue()
                        .equals(newNodes.get(i).getAttributes().getNamedItem("id").getNodeValue())) {
                    root.replaceChild(oldDoc.adoptNode(newNodes.get(i).cloneNode(true)), oldNodes.get(i)); //replace new node with old node
                } else {
                    //System.out.println(i + "equal");
                }
            }
            //        * All not maching "id's" will be replaced
        } else if (oldNodes.size() == newNodes.size()) {
            for (int i = 0; i < oldNodes.size(); i++) {
                if (!oldNodes.get(i).getAttributes().getNamedItem("id").getNodeValue()
                        .equals(newNodes.get(i).getAttributes().getNamedItem("id").getNodeValue())) {
                    root.replaceChild(oldDoc.adoptNode(newNodes.get(i).cloneNode(true)), oldNodes.get(i));// replace old with new node
                } else {
                    //System.out.println(i + " equal");
                }
            }
            //        * All extra nodes will be apended
            //        * All not maching "id's" will be replaced
        } else if (oldNodes.size() < newNodes.size()) {
            for (int i = 0; i < newNodes.size(); ++i) {
                if (i >= oldNodes.size()) {
                    root.appendChild(oldDoc.adoptNode(newNodes.get(i).cloneNode(true))); //append extra new node
                } else if (!newNodes.get(i).getAttributes().getNamedItem("id").getNodeValue()
                        .equals(oldNodes.get(i).getAttributes().getNamedItem("id").getNodeValue())) {
                    root.replaceChild(oldDoc.adoptNode(newNodes.get(i).cloneNode(true)), oldNodes.get(i));//replace old with new node
                } else {
                    //System.out.println(i + "equal");
                }
            }
        }
        writeDocument(oldDoc, pathXml);
    }

    /**
     * This method is going to update file called "Anlagenbaum.xml" The updates
     * that are done to this file are essential when adding new site witch is
     * done automatically. It needs to be done for GMA-manager software to
     * detect changes/ that folder/site has been added.
     *
     * @throws javax.xml.parsers.ParserConfigurationException
     * @throws org.xml.sax.SAXException
     * @throws javax.xml.transform.TransformerException
     * @throws java.io.IOException
     */
    public void updateAnlage()
            throws DOMException, ParserConfigurationException, TransformerException, IOException, SAXException {
        File anlageFile = new File(home.getAbsolutePath() + slash + "Anlagenbaum.xml");
        DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
        Document doc = docBuilder.parse(anlageFile);
        // Get the root element
        Node root = doc.getFirstChild();
        NodeList staff = doc.getElementsByTagName("GraphicsContainerNode");
        ArrayList<String> staffList = new ArrayList<>();

        for (int i = 0; i < staff.getLength(); i++) {
            NamedNodeMap attr = staff.item(i).getAttributes();
            Node nodeAttr = attr.getNamedItem("id");
            String content = nodeAttr.getTextContent();
            staffList.add(content);
        }

        File[] siteName = home.listFiles(directoryFilter);
        ArrayList<String> siteNameList = new ArrayList<>();

        for (File f : siteName) {
            siteNameList.add(f.getName());
        }

        Collection site = siteNameList;
        Collection staffCollection = staffList;

        if (staff.getLength() == 0) {
            for (String s : siteNameList) {
                Element graphicsNode = doc.createElement("GraphicsContainerNode");
                graphicsNode.setAttribute("id", s);
                graphicsNode.setAttribute("load", s + slash + s);
                graphicsNode.setAttribute("name", s);
                root.appendChild(graphicsNode);
            }
        } else if (staff.getLength() <= siteName.length || staff.getLength() > 0) {
            site.removeAll(staffCollection);
            for (Object s : site) {
                Element graphicsNode = doc.createElement("GraphicsContainerNode");
                graphicsNode.setAttribute("id", s.toString());
                graphicsNode.setAttribute("load", s.toString() + slash + s.toString());
                graphicsNode.setAttribute("name", s.toString());
                root.appendChild(graphicsNode);
            }
        }
        writeDocument(doc, anlageFile);
        log.info("updating site tree successful!");
    }

    /**
     * This method filters given pathName for proper pathname for OS not to be
     * confused by characters that are not supported. Also it provides names and
     * type of detectors that are in specific location.
     *
     * @param doc
     * @param out
     * @throws java.io.IOException
     * @throws javax.xml.transform.TransformerException
     */
    //P.S should work well junit test could be to compare number of items that are present
    //in the file to compare with number that has been readed my this function
    //Is able to print org.w3c.dom.Document out.
    public void printDocument(Document doc, OutputStream out) throws IOException, TransformerException {
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer transformer = tf.newTransformer();
        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
        transformer.setOutputProperty(OutputKeys.METHOD, "xml");
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
        transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");

        transformer.transform(new DOMSource(doc), new StreamResult(new OutputStreamWriter(out, "UTF-8")));
    }

    /**
     *
     * Writes Document object to specified path as file
     *
     * @param doc
     * @param path
     * @throws TransformerException
     * @throws IOException
     * @throws DOMException
     * @throws ParserConfigurationException
     * @throws SAXException
     */
    private void writeDocument(Document doc, File path)
            throws TransformerException, IOException, DOMException, ParserConfigurationException, SAXException {
        Transformer transformer = TransformerFactory.newInstance().newTransformer();
        transformer.setOutputProperty(OutputKeys.INDENT, "no");
        transformer.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1");
        DOMSource source = new DOMSource(doc);
        StreamResult result = new StreamResult(new StringWriter());
        transformer.transform(source, result);

        File toCheck = path;
        if (!path.getAbsolutePath().endsWith(".xml")) {
            toCheck = new File(path.getAbsolutePath() + slash + path.getName() + ".xml");
        }

        try (FileOutputStream xmlfile = new FileOutputStream(toCheck);) {
            if (toCheck.exists()) {
                xmlfile.write(result.getWriter().toString().getBytes());
            } else {
                toCheck.createNewFile();
                xmlfile.write(result.getWriter().toString().getBytes());
            }
        }
    }
}