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

org.openmdx.portal.utility.CodeUtility Maven / Gradle / Ivy

The newest version!
/*
 * ====================================================================
 * Project:     openMDX/Portal, http://www.openmdx.org/
 * Description: CodeUtility
 * Owner:       the original authors.
 * ====================================================================
 *
 * This software is published under the BSD license as listed below.
 * 
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions 
 * are met:
 * 
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * 
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in
 *   the documentation and/or other materials provided with the
 *   distribution.
 * 
 * * Neither the name of the openMDX team nor the names of the 
 *   contributors to openMDX may be used to endorse or promote products 
 *   derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 * 
 * ------------------
 * 
 * This product includes software developed by the Apache Software
 * Foundation (http://www.apache.org/).
 * 
 * This product includes yui, the Yahoo! UI Library
 * (License - based on BSD).
 *
 */
package org.openmdx.portal.utility;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import javax.resource.ResourceException;
import javax.resource.cci.MappedRecord;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.openmdx.application.xml.Importer;
import org.openmdx.base.exception.ServiceException;
import org.openmdx.base.naming.Path;
import org.openmdx.base.rest.cci.ObjectRecord;
import org.openmdx.base.rest.spi.Object_2Facade;
import org.openmdx.kernel.exception.Throwables;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * Command line utility which supports the management of openMDX/Portal Code code files:
 * 
    *
  • merge: merges locale separated code files (en_US, de_DE) to one merged file.
  • *
  • split: splits a merged code file to locale separated files.
  • *
*

*/ @SuppressWarnings("unchecked") public class CodeUtility { /** * Lookup code. * * @param document * @param lookupContainerName * @param lookupCode * @return */ private Map lookupCode( Document document, String lookupContainerName, String lookupCode ) { Map codeEntry = new HashMap<>(); NodeList containerNodes = document.getElementsByTagName("CodeValueContainer"); for(int i = 0; i < containerNodes.getLength(); i++) { org.w3c.dom.Node containerNode = containerNodes.item(i); org.w3c.dom.NamedNodeMap containerNodeAttributes = containerNode.getAttributes(); org.w3c.dom.Attr containerNodeName = (org.w3c.dom.Attr)containerNodeAttributes.getNamedItem("name"); if( (containerNodeName != null) && lookupContainerName.equals(containerNodeName.getValue()) ) { org.w3c.dom.NodeList codeValueEntryNodes = containerNode.getChildNodes(); for(int j = 0; j < codeValueEntryNodes.getLength(); j++) { org.w3c.dom.Node codeValueEntryNode = codeValueEntryNodes.item(j); if(codeValueEntryNode.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) { if("CodeValueEntry".equals(codeValueEntryNode.getNodeName())) { org.w3c.dom.NamedNodeMap codeValueEntryNodeAttributes = codeValueEntryNode.getAttributes(); org.w3c.dom.Attr codeValueEntryNodeName = (org.w3c.dom.Attr)codeValueEntryNodeAttributes.getNamedItem("code"); if( (codeValueEntryNodeName != null) && (lookupCode.equals(codeValueEntryNodeName.getValue())) ) { org.w3c.dom.NodeList attributeNodes = codeValueEntryNode.getChildNodes(); for(int k = 0; k < attributeNodes.getLength(); k++) { org.w3c.dom.Node attributeNode = attributeNodes.item(k); if(attributeNode.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) { if(attributeNode.hasChildNodes()) { codeEntry.put( attributeNode.getNodeName(), attributeNode.getFirstChild().getNodeValue() ); } } } } } else { System.out.println("WARNING: skipping node " + codeValueEntryNode.getNodeName()); } } } } } return codeEntry; } /** * Split merged code files per locale. * * @param locale * @param sourceDir * @param targetDir * @throws ServiceException */ protected void split( List locale, File sourceDir, File targetDir ) throws ServiceException { String en_US_Dir = targetDir.getAbsolutePath() + File.separatorChar + "en_US"; System.out.println("sourceDir=" + sourceDir.getAbsolutePath()); File[] en_US_files = new File(en_US_Dir).listFiles(); if(en_US_files == null) { System.out.println("ERROR: directory not found: " + en_US_Dir); return; } // en_US files are leading. process all files for(int u = 0; u < en_US_files.length; u++) { // read files containing locale-specific texts and add to en_US Map codes = new LinkedHashMap(); System.out.println("Loading " + en_US_files[u]); try { Importer.importObjects( Importer.asTarget(codes), Importer.asSource(en_US_files[u]) ); } catch(ServiceException e) { e.log(); System.out.println("STATUS: " + e.getMessage()); } catch(Exception e) { Throwables.log(e); System.out.println("STATUS: " + e.getMessage()); } // Load merged file File file = new File(sourceDir.getAbsolutePath() + File.separatorChar + en_US_files[u].getName()); if(file.exists()) { try { System.out.println("Loading " + file.getAbsolutePath()); org.w3c.dom.Document mergedCodes = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(file); for(Iterator i = codes.values().iterator(); i.hasNext(); ) { MappedRecord code = i.next(); Object_2Facade codeFacade; try { codeFacade = Object_2Facade.newInstance(code); } catch (ResourceException e) { throw new ServiceException(e); } Map mergedCode = this.lookupCode( mergedCodes, codeFacade.getPath().getParent().getParent().getLastSegment().toClassicRepresentation(), codeFacade.getPath().getLastSegment().toClassicRepresentation() ); for(int j = 1; j < locale.size(); j++) { // skip en_US String shortText = (String)mergedCode.get(locale.get(j) + "_short"); String longText = (String)mergedCode.get(locale.get(j) + "_long"); codeFacade.attributeValuesAsList("shortText").add(shortText == null ? "" : shortText); codeFacade.attributeValuesAsList("longText").add(longText == null ? "" : longText); } } } catch(ParserConfigurationException e) { System.err.println("ParserConfigurationException: Can not load file " + file.getAbsolutePath()); } catch(SAXException e) { System.err.println("SAXException: Can not load file " + file.getAbsolutePath()); } catch(IOException e) { System.err.println("IOException: Can not load file " + file.getAbsolutePath()); } // split and store codes as XML for(int j = 1; j < locale.size(); j++) { // never write base locale 0 String outFileName = targetDir.getAbsolutePath() + File.separatorChar + locale.get(j) + File.separatorChar + en_US_files[u].getName(); try { File outFile = new File(outFileName); if(outFile.exists()) { File renamed = new File(outFile.getParent() + File.separatorChar + ".#" + outFile.getName()); if(!outFile.renameTo(renamed)) { System.out.println("WARNING: Can not move file " + outFile.getAbsolutePath() + " to " + renamed.getAbsolutePath() + ". Skipping"); continue; } } else if(!outFile.getParentFile().exists()) { if(!outFile.getParentFile().mkdir()) { System.out.println("WARNING: Can not create directory " + outFile.getParentFile().getAbsolutePath() + ". Skipping"); continue; } } System.out.println("writing file " + outFileName); try( Writer w = new OutputStreamWriter(new FileOutputStream(outFileName), "UTF-8"); Writer fw = new XMLWriter(w); ){ String providerName ="CRX"; // default String segmentName = "Standard"; // default if(codes.size() > 0) { MappedRecord obj = codes.values().iterator().next(); Path objPath = Object_2Facade.getPath(obj); providerName = objPath.getSegment(2).toClassicRepresentation(); segmentName = objPath.getSegment(4).toClassicRepresentation(); } String s = null; s = "\n" + "\n" + " <_object/>\n" + " <_content>\n" + " \n" + " \n" + " <_object/>\n" + " <_content>\n" + " \n" + " \n" + " <_object/>\n" + " <_content>\n" + " \n"; w.write(s, 0, s.length()); boolean firstContainer = true; for(Iterator i = codes.values().iterator(); i.hasNext(); ) { MappedRecord element = i.next(); Object_2Facade elementFacade; try { elementFacade = Object_2Facade.newInstance(element); } catch (ResourceException e) { throw new ServiceException(e); } if("org:opencrx:kernel:code1:CodeValueContainer".equals(elementFacade.getObjectClass())) { if(!firstContainer) { s = " \n" + " \n" + " \n"; w.write(s, 0, s.length()); } s = " \n" + " <_object/>\n" + " <_content>\n" + " \n"; w.write(s, 0, s.length()); firstContainer = false; } else if("org:opencrx:kernel:code1:CodeValueEntry".equals(elementFacade.getObjectClass())) { // only write if there are texts if( ((elementFacade.attributeValuesAsList("shortText").size() > j) && (((String)elementFacade.attributeValuesAsList("shortText").get(j)).length() > 0)) || ((elementFacade.attributeValuesAsList("longText").size() > j) && (((String)elementFacade.attributeValuesAsList("longText").get(j)).length() > 0)) ) { String shortText = elementFacade.attributeValuesAsList("shortText").size() > j ? (String)elementFacade.attributeValuesAsList("shortText").get(j) : ""; String longText = elementFacade.attributeValuesAsList("longText").size() > j ? (String)elementFacade.attributeValuesAsList("longText").get(j) : ""; s = " \n" + " <_object>\n"; w.write(s, 0, s.length()); if(shortText.length() > 0) { s = " \n" + " <_item>"; w.write(s, 0, s.length()); s = shortText; fw.write(s, 0, s.length()); s = "\n" + " \n"; w.write(s, 0, s.length()); } if(longText.length() > 0) { s = " \n" + " <_item>"; w.write(s, 0, s.length()); s = longText; fw.write(s, 0, s.length()); s = "\n" + " \n"; w.write(s, 0, s.length()); } s = " \n" + " <_content/>\n" + " \n"; w.write(s, 0, s.length()); } } } if(!firstContainer) { s = " \n" + " \n" + " \n"; w.write(s, 0, s.length()); } s = " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; w.write(s, 0, s.length()); } } catch(FileNotFoundException e) { System.err.println("Can not create file " + outFileName); } catch(UnsupportedEncodingException e) { System.err.println("Can not create file with encoding UTF-8 " + outFileName); } catch(IOException e) { System.err.println("Error writing to file " + outFileName); } } } // Skip if merged file does not exist else { System.out.println("File does not exist. Skipping " + file.getAbsolutePath()); } } } /** * Merge code files. * * @param locale * @param sourceDir * @param targetDir * @throws ServiceException */ protected void merge( List locale, File sourceDir, File targetDir ) throws ServiceException { String en_US_Dir = sourceDir.getAbsolutePath() + File.separatorChar + "en_US"; System.out.println("sourceDir=" + sourceDir.getAbsolutePath()); File[] en_US_files = new File(en_US_Dir).listFiles(); if(en_US_files == null) { System.out.println("ERROR: directory not found: " + en_US_Dir); return; } // Process all code files for(int u = 0; u < en_US_files.length; u++) { // Get all locale specific files for en_US_files[k] Map mergedCodes = new TreeMap(); Set codeValueContainers = new HashSet<>(); // collect CodeValueContainer which are required in next step for(int i = 0; i < locale.size(); i++) { // Read entries File file = new File(sourceDir.getAbsolutePath() + File.separatorChar + locale.get(i) + File.separatorChar + en_US_files[u].getName()); Map codes = new HashMap(); if(file.exists()) { System.out.println("loading " + file); try { Importer.importObjects( Importer.asTarget(codes), Importer.asSource(file) ); } catch(ServiceException e) { e.log(); System.out.println("STATUS: " + e.getMessage()); } catch(Exception e) { Throwables.log(e); System.out.println("STATUS: " + e.getMessage()); } } // Merge entries Set keySet = i == 0 ? codes.keySet() : mergedCodes.keySet(); try { for(Iterator j = keySet.iterator(); j.hasNext(); ) { Path key = (Path)j.next(); // merge entry if(mergedCodes.get(key) != null) { MappedRecord mergedCodeEntry = mergedCodes.get(key); Object_2Facade mergedCodeEntryFacade = Object_2Facade.newInstance(mergedCodeEntry); if(mergedCodeEntryFacade.getObjectClass().endsWith("CodeValueEntry")) { MappedRecord codeEntry = codes.get(key); Object_2Facade codeEntryFacade = Object_2Facade.newInstance(codeEntry); mergedCodeEntryFacade.attributeValuesAsList("shortText").add( (codeEntryFacade != null && !codeEntryFacade.attributeValuesAsList("shortText").isEmpty()) ? codeEntryFacade.attributeValue("shortText") : "" // empty string as default ); mergedCodeEntryFacade.attributeValuesAsList("longText").add( (codeEntryFacade != null && !codeEntryFacade.attributeValuesAsList("longText").isEmpty()) ? codeEntryFacade.attributeValue("longText") : "" // empty string as default ); } } else if(i == 0) { // add if it does not exist. Only add for locale=0 (en_US) MappedRecord entry = codes.get(key); if(Object_2Facade.getObjectClass(entry).endsWith("CodeValueContainer")) { codeValueContainers.add(entry); } else { mergedCodes.put( key, entry ); } } else { // locale > 0 requires that locale=0 exists. Complain if it // does not System.err.println("entry " + key + " of locale " + locale.get(i) + " has no corresponding entry for locale " + locale.get(0) + ". Not loading"); } } } catch(Exception e) { System.err.println("Can not import. Reason is " + e.getMessage()); } } // Try numeric sort of entries Map,MappedRecord> sortedCodes = new TreeMap<>(); for(Iterator> i = mergedCodes.entrySet().iterator(); i.hasNext(); ) { Map.Entry entry = i.next(); String codeKey = ((Path)entry.getKey()).getLastSegment().toClassicRepresentation(); try { sortedCodes.put( Integer.valueOf(codeKey), entry.getValue() ); } catch(NumberFormatException e) { sortedCodes = (Map)mergedCodes; // Dirty, but works for values() only access. Nevertheless assignment to a sortedCodesValues for both cases would be better break; } } // Dump mergedCodes as UTF-8 encoded XML String outFileName = targetDir.getAbsolutePath() + File.separatorChar + en_US_files[u].getName(); try { // rename existing file File outFile = new File(outFileName); if(outFile.exists()) { File renamed = new File(outFile.getParent() + File.separatorChar + ".#" + outFile.getName()); if(!outFile.renameTo(renamed)) { System.out.println("WARNING: can not move file " + outFile.getAbsolutePath() + " to " + renamed.getAbsolutePath() + ". Skipping"); continue; } } else if(!outFile.getParentFile().exists()) { if(!outFile.getParentFile().mkdir()) { System.out.println("WARNING: can not create directory " + outFile.getParentFile().getAbsolutePath() + ". Skipping"); continue; } } System.out.println("writing file " + outFileName); try( Writer w = new OutputStreamWriter(new FileOutputStream(outFileName), "UTF-8"); Writer fw = new XMLWriter(w); ){ String s = null; s = "\n"; w.write(s, 0, s.length()); s = "\n"; w.write(s, 0, s.length()); for(Iterator i = codeValueContainers.iterator(); i.hasNext(); ) { MappedRecord codeValueContainer = i.next(); Path codeValueContainerPath = Object_2Facade.getPath(codeValueContainer); s = " \n"; w.write(s, 0, s.length()); for(Iterator j = sortedCodes.values().iterator(); j.hasNext(); ) { MappedRecord entry = j.next(); Object_2Facade entryFacade; try { entryFacade = Object_2Facade.newInstance(entry); } catch (ResourceException e) { throw new ServiceException(e); } if(codeValueContainerPath.getLastSegment().toClassicRepresentation().equals(entryFacade.getPath().getParent().getParent().getLastSegment().toClassicRepresentation())) { s = " \n"; w.write(s, 0, s.length()); for(int k = 0; k < locale.size(); k++) { // shortText s = " <" + locale.get(k) + "_short>"; w.write(s, 0, s.length()); s = k < entryFacade.attributeValuesAsList("shortText").size() ? (String)entryFacade.attributeValuesAsList("shortText").get(k) : ""; fw.write(s, 0, s.length()); s = "\n"; w.write(s, 0, s.length()); // longText s = " <" + locale.get(k) + "_long>"; w.write(s, 0, s.length()); s = k < entryFacade.attributeValuesAsList("longText").size() ? (String)entryFacade.attributeValuesAsList("longText").get(k) : ""; fw.write(s, 0, s.length()); s = "\n"; w.write(s, 0, s.length()); } s = " \n"; w.write(s, 0, s.length()); } } s = " \n"; w.write(s, 0, s.length()); } s = "\n"; w.write(s, 0, s.length()); } } catch(FileNotFoundException e) { System.err.println("can not create file " + outFileName); } catch(UnsupportedEncodingException e) { System.err.println("can not create file with encoding UTF-8 " + outFileName); } catch(IOException e) { System.err.println("error writing to file " + outFileName); } } } /** * Run code utility. * * @param args * @throws ServiceException */ protected void run( String[] args ) throws ServiceException { this.locales = new ArrayList<>(); this.sourceDir = new File("."); this.targetDir = new File("."); String command = "merge"; for(int i = 0; i < args.length; i++) { if("--locale".equals(args[i]) && (i + 1 < args.length)) { String[] locales = args[i+1].split("/"); this.locales.addAll(Arrays.asList(locales)); } // sourceDir else if("--sourceDir".equals(args[i]) && (i + 1 < args.length)) { this.sourceDir = new File(args[i+1]); } // targetDir else if("--targetDir".equals(args[i]) && (i + 1 < args.length)) { this.targetDir = new File(args[i+1]); } else if("--split".equals(args[i])) { command = "split"; } else if("--merge".equals(args[i])) { command = "merge"; } } if(this.locales.isEmpty() || !"en_US".equals(this.locales.get(0))) { this.locales.add(0, "en_US"); } if("merge".equals(command)){ this.merge( this.locales, this.sourceDir, this.targetDir ); } else if("split".equals(command)){ this.split( this.locales, this.sourceDir, this.targetDir ); } } /** * Main code utility. * * @param args * @throws ServiceException */ public static void main( String[] args ) throws ServiceException { new CodeUtility().run(args); } //------------------------------------------------------------------------- // Members //------------------------------------------------------------------------- private List locales = null; private File sourceDir = null; private File targetDir = null; } //--- End of File -----------------------------------------------------------





© 2015 - 2024 Weber Informatics LLC | Privacy Policy