RootNodeList.java
/*
** Module : RootNodeList.java
** Abstract : maintains a project-specific list of root entry point procedures
**
** Copyright (c) 2005-2018, Golden Code Development Corporation.
**
** -#- -I- --Date-- --JPRM-- -----------------------------Description-----------------------------
** 001 GES 20050314 @20312 Created initial version which has support
** for a persistable XML root node list.
** 002 ECF 20050317 @20418 Constructor now throws ConfigurationException
** if root node list file parameter is not found
** in configuration.
** 003 ECF 20050421 @20809 Import p2j.xml package to use XmlHelper.
** 004 GES 20090429 @42063 Match package and class name changes.
** 005 GES 20090515 @42231 Import change.
** 006 CA 20140313 Added possibility to specify the files in a folder as entry-points.
** 007 ECF 20160407 Added TODO in c'tor to check for rootlist hint.
** 008 GES 20170531 Fix loading when current directory is not the same as project home.
** 009 CA 20170922 Fixed a path compatibility when generating the callgraph on windows.
** 010 CA 20181128 Fixed rootlist file calculation when folders are used.
*/
/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Affero General Public License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
**
** Additional terms under GNU Affero GPL version 3 section 7:
**
** Under Section 7 of the GNU Affero GPL version 3, the following additional
** terms apply to the works covered under the License. These additional terms
** are non-permissive additional terms allowed under Section 7 of the GNU
** Affero GPL version 3 and may not be removed by you.
**
** 0. Attribution Requirement.
**
** You must preserve all legal notices or author attributions in the covered
** work or Appropriate Legal Notices displayed by works containing the covered
** work. You may not remove from the covered work any author or developer
** credit already included within the covered work.
**
** 1. No License To Use Trademarks.
**
** This license does not grant any license or rights to use the trademarks
** Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
** of Golden Code Development Corporation. You are not authorized to use the
** name Golden Code, FWD, or the names of any author or contributor, for
** publicity purposes without written authorization.
**
** 2. No Misrepresentation of Affiliation.
**
** You may not represent yourself as Golden Code Development Corporation or FWD.
**
** You may not represent yourself for publicity purposes as associated with
** Golden Code Development Corporation, FWD, or any author or contributor to
** the covered work, without written authorization.
**
** 3. No Misrepresentation of Source or Origin.
**
** You may not represent the covered work as solely your work. All modified
** versions of the covered work must be marked in a reasonable way to make it
** clear that the modified work is not originating from Golden Code Development
** Corporation or FWD. All modified versions must contain the notices of
** attribution required in this license.
*/
package com.goldencode.p2j.uast;
import java.io.*;
import java.util.*;
import org.w3c.dom.*;
import com.goldencode.ast.*;
import com.goldencode.util.*;
import com.goldencode.p2j.cfg.*;
import com.goldencode.p2j.util.*;
/**
* Reads a project-specific list of root entry point procedures.
* <p>
* The list is flat with a root element of 'roots' and all 'node' elements
* enclosed within that root element. Each node element has a single
* 'filename' attribute with the root node file name. No nesting of nodes
* is provided or supported.
*/
public class RootNodeList
{
/** Key for the global root node list filename configuration parameter. */
private static final String ROOTFILE_KEY = "rootlist";
/** Root element containing the list. */
private static final String ELEM_ROOT = "roots";
/** Represents a single root entry point. */
private static final String ELEM_NODE = "node";
/** The filename that is associated with a root node. */
private static final String ATTR_FILE = "filename";
/** The folder name that is associated with a node. */
private static final String ATTR_FOLDER = "folder";
/** Attribute flag indicating if a folder will be searched recursively. */
private static final String ATTR_RECURSIVE = "recursive";
/** The pattern used to list files from a folder. */
private static final String ATTR_PATTERN = "pattern";
/** XML filename for persisting the registry. */
private File file = null;
/** Stores the root node list. */
private ArrayList<String> nodes = null;
/**
* Constructor which looks up the root node list filename and initializes
* its data structures based on reading that file, if it exists. The
* filename is stored in the global configuration.
*
* @throws ConfigurationException
* if the root node list file is not configured properly.
* @throws AstException
* if the XML parser has a failure during parsing or in its
* file system operations.
* @throws FileNotFoundException
* if a root file or folder does not exist.
*/
public RootNodeList()
throws ConfigurationException,
AstException,
FileNotFoundException
{
String rootNodePath = Configuration.getParameter(ROOTFILE_KEY);
if (rootNodePath == null)
{
// TODO: check UAST hints
throw new ConfigurationException(
"Root node list file is not configured properly");
}
file = new File(Configuration.forceHome(rootNodePath));
// try to load the persisted root node list
if (file.exists())
load();
}
/**
* Accesses the list of root nodes as read from the master XML file.
*
* @return The root node list of filenames or <code>null</code> if
* there are no entries in the list.
*/
public String[] getList()
{
if (nodes == null)
return null;
return (String[])nodes.toArray(new String[0]);
}
/**
* Read the source XML document and build the list from the stored
* elements.
*
* @throws AstException
* if the XML parser has a failure during parsing or in its
* file system operations.
* @throws IllegalArgumentException
* if the input file is invalid or doesn't exist.
* @throws FileNotFoundException
* if a root file or folder does not exist.
*/
private void load()
throws AstException,
FileNotFoundException
{
Document dom = null;
Element root = null;
try
{
if (file.isFile())
{
dom = XmlHelper.parse(file);
root = dom.getDocumentElement();
}
else
{
throw new AstException("Bogus root node list " +
file.toString());
}
}
catch (Exception excpt)
{
throw new AstException(
"Error loading root node XML file: " + file.toString(), excpt);
}
NodeList list = root.getElementsByTagName(ELEM_NODE);
int len = list.getLength();
// leave our list as null, if there are no entries
if (len > 0)
{
nodes = new ArrayList<>();
}
for (int i = 0; i < len; i++)
{
Element elem = (Element) list.item(i);
String name = elem.getAttribute(ATTR_FILE);
if (name == null || name.trim().length() == 0)
{
name = elem.getAttribute(ATTR_FOLDER);
File folder = new File(Configuration.forceHome(name));
if (folder == null || !folder.exists())
{
throw new FileNotFoundException("Folder '" + name + "' does not exist!");
}
String pattern = elem.getAttribute(ATTR_PATTERN);
if (pattern == null || pattern.trim().length() == 0)
{
pattern = "*.ast";
}
boolean recursive = "true".equalsIgnoreCase(elem.getAttribute(ATTR_RECURSIVE));
FileSpecList spec = new FileSpecList(folder, pattern, recursive);
for (String filename : spec.listFilenames())
{
filename = Configuration.normalizeFilename(filename);
nodes.add(filename);
}
}
else
{
File file = new File(Configuration.forceHome(name));
if (!file.exists())
{
throw new FileNotFoundException("File '" + name + "' does not exist!");
}
file = new File(name);
nodes.add(file.getPath());
}
}
}
}