Java tutorial
/* * 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()); } } } }