Package gap.odl

Source Code of gap.odl.Class

/*
* Gap Data
* Copyright (C) 2009 John Pritchard
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 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
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*/
package gap.odl;

import jauk.Pattern;

import gap.service.Classes;
import gap.service.od.ClassDescriptor;
import static gap.service.od.ClassDescriptor.Relation.Type.*;
import gap.service.od.FieldDescriptor;
import gap.service.od.ImportDescriptor;
import gap.service.od.MethodDescriptor;
import gap.service.od.PackageDescriptor;

import java.io.IOException;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;

/**
* <h3>Purpose</h3>
*
* To model the persistent fields of a class for integration with
* {@link gap.data.BigTable}.  This package will generate the Java
* source code for the class subclassing {@link gap.data.BigTable}.
*
* <h3>Syntax</h3>
*
* <ul>
*
* <li> Line comments starting with '#' and '//'.  C/Java style
* multiline comments.  </li>
*
* <li> Package statement from JPL.  Optionally terminated by
* semicolon. </li>
*
* <li> Import expression from JPL, but employing '$' inner class name
* delimeters.  Optionally terminated by semicolon. </li>
*
* <li> Class expression: opening declaration "'class' Classname '{' "
* on one line.  A list of fields, one per line.  A closing
* declaration '}' on a line.
* The class declaration line can optionally override the default
* class serialized version number of one with the expression "'class'
* Classname 'version' number '{'" for number in base ten requiring no
* more than 64 bits storage. </li>
*
* <li> Each field is a class name, space, field name.  Optionally
* terminated by semicolon.
*
* A primary unique field may be qualified with the keyword
* <code>"*unique"</code>.  These fields have type String.
*
* The unique qualifier causes the field to be employed as a primary
* lookup identifier.
*
* Each class is expected to have one (and only one) of each.  </li>
*
* </ul>
*
* <h3>Example</h3>
*
* <pre>
* package foo;
* path /barz;
*
* import java.io.*;
*
* class Bar version 1
*   implements AnInterface
*   implements AndAnotherInterface
* {
*   *unique String name;
*   Serializable value;
* }
* </pre>
*
* <h3>Notes</h3>
*
* Field types must resolve at runtime to serializable types. 
*
* It's not incorrect to employ the java lang Object type, however
* it's more precise to employ the Serializable type in such a case.
*
*
* @author jdp
*/
public final class Class
    extends Object
    implements ClassDescriptor.Version,
               ClassDescriptor.Implements,
               ClassDescriptor.Path,
               ClassDescriptor.Relation,
               ClassDescriptor.WithPackage,
               ClassDescriptor.WithImports
{
    public final static Pattern Open = new jauk.Re("<_>*(class|parent|child) [^{]*\\{<Newline>");


    public enum Attribute {
        VERSION, IMPLEMENTS, PARENT, CHILD, UNKNOWN;

        public final static Attribute For(String name){
            if (null == name)
                return Attribute.UNKNOWN;
            else {
                try {
                    return Attribute.valueOf(name.toUpperCase());
                }
                catch (RuntimeException exc){
                   
                    return Attribute.UNKNOWN;
                }
            }
        }
    }

    public final gap.odl.Package pack;

    public final gap.odl.Path path;

    public final gap.odl.Parent parent;

    public final lxl.List<Child> children = new lxl.ArrayList<Child>();

    public final String name, nameDecamel;

    public final Relation.Type relation;

    public final String version;

    public final lxl.List<ImportDescriptor> imports = new lxl.ArrayList<ImportDescriptor>();

    private gap.odl.Comment comment;

    public final lxl.List<Object> interfaces = new lxl.ArrayList<Object>();

    public final lxl.List<FieldDescriptor> fields = new lxl.ArrayList<FieldDescriptor>();

    public final lxl.List<MethodDescriptor> methods = new lxl.ArrayList<MethodDescriptor>();

    private String definitionClassName;


    public Class(Reader reader)
        throws IOException, Syntax
    {
        super();
        gap.odl.Package pack = null;
        gap.odl.Path path = null;
        String spec = null, name = null;
        gap.odl.Import imp = null;
        gap.odl.Field field = null;
        long version = 1L;
        gap.odl.Parent parent = null;

        while (true){
            try {
                if (null == pack)
                    pack = new gap.odl.Package(reader);
                else if (null == path)
                    path = new gap.odl.Path(reader);
                else if (null == name){
                    try {
                        imp = new gap.odl.Import(reader);
                        this.imports.add(imp);
                    }
                    catch (Jump local){
                        reader.comment(local);
                        this.comment = reader.comment();
                        String open = reader.next(Open);
                        if (null != open){
                            StringTokenizer strtok = new StringTokenizer(open, " \t\r\n{");
                            spec = strtok.nextToken();
                            name = strtok.nextToken();
                            while(strtok.hasMoreTokens()){
                                String token = strtok.nextToken();
                                switch(Attribute.For(token)){
                                case VERSION:
                                    version = Long.decode(strtok.nextToken());
                                    break;
                                case IMPLEMENTS:
                                    this.interfaces.add(new gap.odl.Interface(strtok.nextToken(), pack, this.imports));
                                    break;
                                case PARENT:
                                    parent = new gap.odl.Parent(strtok.nextToken());
                                    break;
                                case CHILD:
                                    this.children.add(new gap.odl.Child(strtok.nextToken()));
                                    break;
                                case UNKNOWN:
                                    throw new Syntax("Malformed ODL class declaration in '"+open+"' at '"+token+"' in '"+reader.sourcepath+"'.");
                                }
                            }
                        }
                        else
                            throw new Syntax("ODL class declaration not found in '"+reader.sourcepath+"'.");
                    }
                }
                else {
                    field = new gap.odl.Field(reader,this,pack);
                    this.fields.add(field);
                }
            }
            catch (Jump terminal){
                reader.comment(terminal);
                break;
            }
        }

        if (null != pack)
            this.pack = pack;
        else
            throw new Syntax("Syntax error missing package in '"+reader.sourcepath+"'.");

        this.parent = parent;
        this.path = path;

        if (null != spec && null != name){

            this.name = name;
            this.nameDecamel = Decamel(name);

            if ("child".equals(spec) || (null != parent)){

                this.relation = Relation.Type.Child;
            }
            else if ("parent".equals(spec) || (0 < this.children.size()))

                this.relation = Relation.Type.Parent;
            else
                this.relation = Relation.Type.None;
        }
        else
            throw new Syntax("Syntax error missing class declaration in '"+reader.sourcepath+"'.");

        this.version = String.valueOf(version);

        return;
    }


    public String getName(){
        return this.name;
    }
    public boolean hasPath(){
        return true;
    }
    public String getPath(){
        return this.path.getName();
    }
    public boolean hasRelation(){
        return true;
    }
    public Relation.Type getRelation(){
        return this.relation;
    }
    public boolean isRelationPrimary(){
        switch (this.relation){
        case None:
        case Parent:
            return true;
        case Child:
            return false;
        default:
            throw new IllegalStateException();
        }
    }
    public boolean isRelationSecondary(){
        switch (this.relation){
        case None:
        case Parent:
            return false;
        case Child:
            return true;
        default:
            throw new IllegalStateException();
        }
    }
    public boolean hasVersion(){
        return (null != this.version);
    }
    public Long getVersion(){
        return new Long(this.version);
    }
    public boolean hasComment(){
        return (null != this.comment);
    }
    public Comment getComment(){
        return this.comment;
    }
    public boolean hasFields(){
        return (!this.fields.isEmpty());
    }
    public lxl.List<FieldDescriptor> getFields(){
        return this.fields;
    }
    public boolean isFieldShort(FieldDescriptor field){
        String fieldType = gap.Objects.StringFromObject(field.getType());
        if (null != fieldType){
            for (gap.odl.Child child: this.children){
                String childName = child.getName();
                if (null != childName && childName.equals(fieldType))
                    return true;
            }
            return false;
        }
        else
            throw new IllegalStateException(String.format("Missing type for field '%s'",field.getName()));
    }
    public boolean hasMethods(){
        return false;
    }
    public lxl.List<MethodDescriptor> getMethods(){
        return this.methods;
    }

    public boolean hasDefinitionClassName(){
        return (null != this.definitionClassName);
    }
    public String getDefinitionClassName(){
        return this.definitionClassName;
    }
    public void setDefinitionClassName(String name){
        this.definitionClassName = name;
    }

    public boolean hasInterfaces(){
        return (!this.interfaces.isEmpty());
    }
    public lxl.List<Object> getInterfaces(){
        return this.interfaces;
    }
    public boolean hasParent(){
        return (null != this.parent);
    }
    public boolean hasNotParent(){
        return (null == this.parent);
    }
    public String getParent(){
        if (null != this.parent)
            return this.parent.getName();
        else
            return null;
    }
    public boolean hasPackage(){
        return true;
    }
    public PackageDescriptor getPackage(){
        return this.pack;
    }
    public String getPackageClassName(){
        final PackageDescriptor pack = this.pack;
        if (null != pack){
            final String pkg = pack.getName();
            if (null != pkg){

                return pkg+'.'+this.name;
            }
        }
        return this.name;
    }
    public boolean hasImports(){
        return (!this.imports.isEmpty());
    }
    public lxl.List<ImportDescriptor> getImports(){
        return this.imports;
    }

    public final static String Decamel(String string){
        if (1 < string.length())
            return (string.substring(0,1).toLowerCase()+string.substring(1));
        else
            return string.toLowerCase();
    }
}
TOP

Related Classes of gap.odl.Class

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.