325N/A/*
325N/A * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
325N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
325N/A *
325N/A * This code is free software; you can redistribute it and/or modify it
325N/A * under the terms of the GNU General Public License version 2 only, as
325N/A * published by the Free Software Foundation. Oracle designates this
325N/A * particular file as subject to the "Classpath" exception as provided
325N/A * by Oracle in the LICENSE file that accompanied this code.
325N/A *
325N/A * This code is distributed in the hope that it will be useful, but WITHOUT
325N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
325N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
325N/A * version 2 for more details (a copy is included in the LICENSE file that
325N/A * accompanied this code).
325N/A *
325N/A * You should have received a copy of the GNU General Public License version
325N/A * 2 along with this work; if not, write to the Free Software Foundation,
325N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
325N/A *
325N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
325N/A * or visit www.oracle.com if you need additional information or have any
325N/A * questions.
325N/A */
325N/A
325N/Apackage com.sun.codemodel.internal;
325N/A
325N/Aimport java.io.BufferedOutputStream;
325N/Aimport java.io.BufferedWriter;
325N/Aimport java.io.File;
325N/Aimport java.io.IOException;
325N/Aimport java.io.OutputStream;
325N/Aimport java.io.PrintWriter;
325N/Aimport java.io.Writer;
325N/Aimport java.lang.annotation.Annotation;
325N/Aimport java.util.ArrayList;
325N/Aimport java.util.HashMap;
325N/Aimport java.util.HashSet;
325N/Aimport java.util.Iterator;
325N/Aimport java.util.List;
325N/Aimport java.util.Map;
325N/Aimport java.util.Set;
325N/Aimport java.util.TreeMap;
325N/Aimport java.util.Collection;
325N/Aimport java.util.Collections;
325N/A
325N/A
325N/A/**
325N/A * A Java package.
325N/A */
325N/Apublic final class JPackage implements JDeclaration, JGenerable, JClassContainer, JAnnotatable, Comparable<JPackage>, JDocCommentable {
325N/A
325N/A /**
325N/A * Name of the package.
325N/A * May be the empty string for the root package.
325N/A */
325N/A private String name;
325N/A
325N/A private final JCodeModel owner;
325N/A
325N/A /**
325N/A * List of classes contained within this package keyed by their name.
325N/A */
325N/A private final Map<String,JDefinedClass> classes = new TreeMap<String,JDefinedClass>();
325N/A
325N/A /**
325N/A * List of resources files inside this package.
325N/A */
325N/A private final Set<JResourceFile> resources = new HashSet<JResourceFile>();
325N/A
325N/A /**
325N/A * All {@link JClass}s in this package keyed the upper case class name.
325N/A *
325N/A * This field is non-null only on Windows, to detect
325N/A * "Foo" and "foo" as a collision.
325N/A */
325N/A private final Map<String,JDefinedClass> upperCaseClassMap;
325N/A
325N/A /**
325N/A * Lazily created list of package annotations.
325N/A */
325N/A private List<JAnnotationUse> annotations = null;
325N/A
325N/A /**
325N/A * package javadoc.
325N/A */
325N/A private JDocComment jdoc = null;
325N/A
325N/A /**
325N/A * JPackage constructor
325N/A *
325N/A * @param name
325N/A * Name of package
325N/A *
325N/A * @param cw The code writer being used to create this package
325N/A *
325N/A * @throws IllegalArgumentException
325N/A * If each part of the package name is not a valid identifier
325N/A */
325N/A JPackage(String name, JCodeModel cw) {
325N/A this.owner = cw;
325N/A if (name.equals(".")) {
325N/A String msg = "Package name . is not allowed";
325N/A throw new IllegalArgumentException(msg);
325N/A }
325N/A
325N/A if(JCodeModel.isCaseSensitiveFileSystem)
325N/A upperCaseClassMap = null;
325N/A else
325N/A upperCaseClassMap = new HashMap<String,JDefinedClass>();
325N/A
325N/A this.name = name;
325N/A }
325N/A
325N/A
325N/A public JClassContainer parentContainer() {
325N/A return parent();
325N/A }
325N/A
325N/A /**
325N/A * Gets the parent package, or null if this class is the root package.
325N/A */
325N/A public JPackage parent() {
325N/A if(name.length()==0) return null;
325N/A
325N/A int idx = name.lastIndexOf('.');
325N/A return owner._package(name.substring(0,idx));
325N/A }
325N/A
325N/A public boolean isClass() { return false; }
325N/A public boolean isPackage() { return true; }
325N/A public JPackage getPackage() { return this; }
325N/A
325N/A /**
325N/A * Add a class to this package.
325N/A *
325N/A * @param mods
325N/A * Modifiers for this class declaration
325N/A *
325N/A * @param name
325N/A * Name of class to be added to this package
325N/A *
325N/A * @return Newly generated class
325N/A *
325N/A * @exception JClassAlreadyExistsException
325N/A * When the specified class/interface was already created.
325N/A */
325N/A public JDefinedClass _class(int mods, String name) throws JClassAlreadyExistsException {
325N/A return _class(mods,name,ClassType.CLASS);
325N/A }
325N/A
325N/A /**
325N/A * {@inheritDoc}
325N/A * @deprecated
325N/A */
325N/A public JDefinedClass _class( int mods, String name, boolean isInterface ) throws JClassAlreadyExistsException {
325N/A return _class(mods,name, isInterface?ClassType.INTERFACE:ClassType.CLASS );
325N/A }
325N/A
325N/A public JDefinedClass _class( int mods, String name, ClassType classTypeVal ) throws JClassAlreadyExistsException {
325N/A if(classes.containsKey(name))
325N/A throw new JClassAlreadyExistsException(classes.get(name));
325N/A else {
325N/A // XXX problems caught in the NC constructor
325N/A JDefinedClass c = new JDefinedClass(this, mods, name, classTypeVal);
325N/A
325N/A if( upperCaseClassMap!=null ) {
325N/A JDefinedClass dc = upperCaseClassMap.get(name.toUpperCase());
325N/A if(dc!=null)
325N/A throw new JClassAlreadyExistsException(dc);
325N/A upperCaseClassMap.put(name.toUpperCase(),c);
325N/A }
325N/A classes.put(name,c);
325N/A return c;
325N/A }
325N/A }
325N/A
325N/A /**
325N/A * Adds a public class to this package.
325N/A */
325N/A public JDefinedClass _class(String name) throws JClassAlreadyExistsException {
325N/A return _class( JMod.PUBLIC, name );
325N/A }
325N/A
325N/A /**
325N/A * Gets a reference to the already created {@link JDefinedClass}.
325N/A *
325N/A * @return null
325N/A * If the class is not yet created.
325N/A */
325N/A public JDefinedClass _getClass(String name) {
325N/A if(classes.containsKey(name))
325N/A return classes.get(name);
325N/A else
325N/A return null;
325N/A }
325N/A
325N/A /**
325N/A * Order is based on the lexicological order of the package name.
325N/A */
325N/A public int compareTo(JPackage that) {
325N/A return this.name.compareTo(that.name);
325N/A }
325N/A
325N/A /**
325N/A * Add an interface to this package.
325N/A *
325N/A * @param mods
325N/A * Modifiers for this interface declaration
325N/A *
325N/A * @param name
325N/A * Name of interface to be added to this package
325N/A *
325N/A * @return Newly generated interface
325N/A */
325N/A public JDefinedClass _interface(int mods, String name) throws JClassAlreadyExistsException {
325N/A return _class(mods,name,ClassType.INTERFACE);
325N/A }
325N/A
325N/A /**
325N/A * Adds a public interface to this package.
325N/A */
325N/A public JDefinedClass _interface(String name) throws JClassAlreadyExistsException {
325N/A return _interface(JMod.PUBLIC, name);
325N/A }
325N/A
325N/A /**
325N/A * Add an annotationType Declaration to this package
325N/A * @param name
325N/A * Name of the annotation Type declaration to be added to this package
325N/A * @return
325N/A * newly created Annotation Type Declaration
325N/A * @exception JClassAlreadyExistsException
325N/A * When the specified class/interface was already created.
325N/A
325N/A */
325N/A public JDefinedClass _annotationTypeDeclaration(String name) throws JClassAlreadyExistsException {
325N/A return _class (JMod.PUBLIC,name,ClassType.ANNOTATION_TYPE_DECL);
325N/A }
325N/A
325N/A /**
325N/A * Add a public enum to this package
325N/A * @param name
325N/A * Name of the enum to be added to this package
325N/A * @return
325N/A * newly created Enum
325N/A * @exception JClassAlreadyExistsException
325N/A * When the specified class/interface was already created.
325N/A
325N/A */
325N/A public JDefinedClass _enum (String name) throws JClassAlreadyExistsException {
325N/A return _class (JMod.PUBLIC,name,ClassType.ENUM);
325N/A }
325N/A /**
325N/A * Adds a new resource file to this package.
325N/A */
325N/A public JResourceFile addResourceFile(JResourceFile rsrc) {
325N/A resources.add(rsrc);
325N/A return rsrc;
325N/A }
325N/A
325N/A /**
325N/A * Checks if a resource of the given name exists.
325N/A */
325N/A public boolean hasResourceFile(String name) {
325N/A for (JResourceFile r : resources)
325N/A if (r.name().equals(name))
325N/A return true;
325N/A return false;
325N/A }
325N/A
325N/A /**
325N/A * Iterates all resource files in this package.
325N/A */
325N/A public Iterator<JResourceFile> propertyFiles() {
325N/A return resources.iterator();
325N/A }
325N/A
325N/A /**
325N/A * Creates, if necessary, and returns the package javadoc for this
325N/A * JDefinedClass.
325N/A *
325N/A * @return JDocComment containing javadocs for this class
325N/A */
325N/A public JDocComment javadoc() {
325N/A if (jdoc == null)
325N/A jdoc = new JDocComment(owner());
325N/A return jdoc;
325N/A }
325N/A
325N/A /**
325N/A * Removes a class from this package.
325N/A */
325N/A public void remove(JClass c) {
325N/A if (c._package() != this)
325N/A throw new IllegalArgumentException(
325N/A "the specified class is not a member of this package," + " or it is a referenced class");
325N/A
325N/A // note that c may not be a member of classes.
325N/A // this happens when someone is trying to remove a non generated class
325N/A classes.remove(c.name());
325N/A if (upperCaseClassMap != null)
325N/A upperCaseClassMap.remove(c.name().toUpperCase());
325N/A }
325N/A
325N/A /**
325N/A * Reference a class within this package.
325N/A */
325N/A public JClass ref(String name) throws ClassNotFoundException {
325N/A if (name.indexOf('.') >= 0)
325N/A throw new IllegalArgumentException("JClass name contains '.': " + name);
325N/A
325N/A String n = "";
325N/A if (!isUnnamed())
325N/A n = this.name + '.';
325N/A n += name;
325N/A
325N/A return owner.ref(Class.forName(n));
325N/A }
325N/A
325N/A /**
325N/A * Gets a reference to a sub package of this package.
325N/A */
325N/A public JPackage subPackage( String pkg ) {
325N/A if(isUnnamed()) return owner()._package(pkg);
325N/A else return owner()._package(name+'.'+pkg);
325N/A }
325N/A
325N/A /**
325N/A * Returns an iterator that walks the top-level classes defined in this
325N/A * package.
325N/A */
325N/A public Iterator<JDefinedClass> classes() {
325N/A return classes.values().iterator();
325N/A }
325N/A
325N/A /**
325N/A * Checks if a given name is already defined as a class/interface
325N/A */
325N/A public boolean isDefined(String classLocalName) {
325N/A Iterator<JDefinedClass> itr = classes();
325N/A while (itr.hasNext()) {
325N/A if ((itr.next()).name().equals(classLocalName))
325N/A return true;
325N/A }
325N/A
325N/A return false;
325N/A }
325N/A
325N/A /**
325N/A * Checks if this package is the root, unnamed package.
325N/A */
325N/A public final boolean isUnnamed() { return name.length() == 0; }
325N/A
325N/A /**
325N/A * Get the name of this package
325N/A *
325N/A * @return
325N/A * The name of this package, or the empty string if this is the
325N/A * null package. For example, this method returns strings like
325N/A * <code>"java.lang"</code>
325N/A */
325N/A public String name() {
325N/A return name;
325N/A }
325N/A
325N/A /**
325N/A * Return the code model root object being used to create this package.
325N/A */
325N/A public final JCodeModel owner() { return owner; }
325N/A
325N/A
325N/A public JAnnotationUse annotate(JClass clazz) {
325N/A if(isUnnamed())
325N/A throw new IllegalArgumentException("the root package cannot be annotated");
325N/A if(annotations==null)
325N/A annotations = new ArrayList<JAnnotationUse>();
325N/A JAnnotationUse a = new JAnnotationUse(clazz);
325N/A annotations.add(a);
325N/A return a;
325N/A }
325N/A
325N/A public JAnnotationUse annotate(Class<? extends Annotation> clazz) {
325N/A return annotate(owner.ref(clazz));
325N/A }
325N/A
325N/A public <W extends JAnnotationWriter> W annotate2(Class<W> clazz) {
325N/A return TypedAnnotationWriter.create(clazz,this);
325N/A }
325N/A
325N/A public Collection<JAnnotationUse> annotations() {
325N/A if (annotations == null)
325N/A annotations = new ArrayList<JAnnotationUse>();
325N/A return Collections.unmodifiableList(annotations);
325N/A }
325N/A
325N/A /**
325N/A * Convert the package name to directory path equivalent
325N/A */
325N/A File toPath(File dir) {
325N/A if (name == null) return dir;
325N/A return new File(dir, name.replace('.', File.separatorChar));
325N/A }
325N/A
325N/A public void declare(JFormatter f ) {
325N/A if (name.length() != 0)
325N/A f.p("package").p(name).p(';').nl();
325N/A }
325N/A
325N/A public void generate(JFormatter f) {
325N/A f.p(name);
325N/A }
325N/A
325N/A
325N/A void build( CodeWriter src, CodeWriter res ) throws IOException {
325N/A
325N/A // write classes
325N/A for (JDefinedClass c : classes.values()) {
325N/A if (c.isHidden())
325N/A continue; // don't generate this file
325N/A
325N/A JFormatter f = createJavaSourceFileWriter(src, c.name());
325N/A f.write(c);
325N/A f.close();
325N/A }
325N/A
325N/A // write package annotations
325N/A if(annotations!=null || jdoc!=null) {
325N/A JFormatter f = createJavaSourceFileWriter(src,"package-info");
325N/A
325N/A if (jdoc != null)
325N/A f.g(jdoc);
325N/A
325N/A // TODO: think about importing
325N/A if (annotations != null){
325N/A for (JAnnotationUse a : annotations)
325N/A f.g(a).nl();
325N/A }
325N/A f.d(this);
325N/A
325N/A f.close();
325N/A }
325N/A
325N/A // write resources
325N/A for (JResourceFile rsrc : resources) {
325N/A CodeWriter cw = rsrc.isResource() ? res : src;
325N/A OutputStream os = new BufferedOutputStream(cw.openBinary(this, rsrc.name()));
325N/A rsrc.build(os);
325N/A os.close();
325N/A }
325N/A }
325N/A
325N/A /*package*/ int countArtifacts() {
325N/A int r = 0;
325N/A for (JDefinedClass c : classes.values()) {
325N/A if (c.isHidden())
325N/A continue; // don't generate this file
325N/A r++;
325N/A }
325N/A
325N/A if(annotations!=null || jdoc!=null) {
325N/A r++;
325N/A }
325N/A
325N/A r+= resources.size();
325N/A
325N/A return r;
325N/A }
325N/A
325N/A private JFormatter createJavaSourceFileWriter(CodeWriter src, String className) throws IOException {
325N/A Writer bw = new BufferedWriter(src.openSource(this,className+".java"));
325N/A return new JFormatter(new PrintWriter(bw));
325N/A }
325N/A}