001    /*
002      * mesopotamia @mesopotamia.version@
003     * Multilingual parser and repository. 
004     * Copyright (C) 2005  Hammurapi Group
005     *
006     * This program is free software; you can redistribute it and/or
007     * modify it under the terms of the GNU Lesser General Public
008     * License as published by the Free Software Foundation; either
009     * version 2 of the License, or (at your option) any later version.
010     *
011     * This program is distributed in the hope that it will be useful,
012     * but WITHOUT ANY WARRANTY; without even the implied warranty of
013     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014     * Lesser General Public License for more details.
015     *
016     * You should have received a copy of the GNU Lesser General Public
017     * License along with this library; if not, write to the Free Software
018     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
019     *
020     * URL: http://http://www.hammurapi.biz
021     * e-Mail: support@hammurapi.biz
022     */
023    package org.mesopotamia;
024    
025    import gnu.trove.TIntHashSet;
026    import gnu.trove.TIntIterator;
027    
028    import java.lang.reflect.InvocationTargetException;
029    import java.sql.ResultSet;
030    import java.sql.SQLException;
031    import java.util.logging.Logger;
032    
033    import org.mesopotamia.sql.LoaderImpl;
034    
035    import biz.hammurapi.config.ConfigurationException;
036    import biz.hammurapi.config.StringConfigurable;
037    import biz.hammurapi.eval.CircularReferenceException;
038    import biz.hammurapi.sql.RowProcessor;
039    import biz.hammurapi.sql.SQLExceptionEx;
040    
041    
042    /**
043     * Holds loader instance
044     * @author Pavel Vlasov
045     * @revision $Revision$
046     */
047    public class LoaderEntry extends LoaderImpl {
048            private Loader loader;
049            private TIntHashSet masters=new TIntHashSet();
050            private RepositoryLanguage repoLanguage;
051            private static final Logger logger = Logger.getLogger(LoaderEntry.class.getName());
052    
053            /**
054             * @param rs
055             * @throws SQLException
056             */
057            public LoaderEntry(RepositoryLanguage repoLanguage, ResultSet rs) throws SQLException {
058                    super(rs);
059                    this.repoLanguage=repoLanguage;
060                    try {
061                            loader=(Loader) repoLanguage.getClassLoader().loadClass(getLoaderClass()).getConstructor(
062                                            new Class[] {RepositoryLanguage.class, LoaderEntry.class}).
063                                                    newInstance(new Object[] {repoLanguage, this});
064                            
065                            if (getLoaderConfig()!=null) {
066                                    if (loader instanceof StringConfigurable) {
067                                            try {
068                                                    ((StringConfigurable) loader).configure(getLoaderConfig(), null);
069                                            } catch (ConfigurationException e) {
070                                                    throw new SQLExceptionEx("Could not configure loader: "+e, e);
071                                            }
072                                    } else {
073                                            logger.warning("Loader "+loader.getClass().getName()+
074                                                            " has not null configuration, but it doesn't implement "+
075                                                            StringConfigurable.class.getName());
076                                    }
077                            }
078                            
079                            repoLanguage.getFactory().getEngine().processLoaderDependencyByDependentLevel(
080                                            rs.getInt("ID"),
081                                            new RowProcessor() {
082    
083                                                    public boolean process(ResultSet rs) throws SQLException {
084                                                            masters.add(rs.getInt("DEPENDS_ON_LEVEL_ID"));
085                                                            return true;
086                                                    }
087                                                    
088                                            });
089                    } catch (InstantiationException e) {
090                            throw new SQLExceptionEx("Cannot instantiate loader "+getLoaderClass(), e);
091                    } catch (IllegalAccessException e) {
092                            throw new SQLExceptionEx("Cannot instantiate loader "+getLoaderClass(), e);
093                    } catch (ClassNotFoundException e) {
094                            throw new SQLExceptionEx("Cannot instantiate loader "+getLoaderClass(), e);
095                    } catch (SecurityException e) {
096                            throw new SQLExceptionEx("Cannot instantiate loader "+getLoaderClass(), e);
097                    } catch (InvocationTargetException e) {
098                            throw new SQLExceptionEx("Cannot instantiate loader "+getLoaderClass(), e);
099                    } catch (NoSuchMethodException e) {
100                            throw new SQLExceptionEx("Cannot instantiate loader "+getLoaderClass(), e);
101                    }
102            }
103    
104            Loader getLoader() {
105                    return loader;
106            }
107            
108            boolean dependsOn(int master, int originalMaster) {
109                    if (getId()==originalMaster) {
110                            throw new CircularReferenceException("Circular reference in loader dependency: ["+originalMaster+"] "+getLevel());
111                    }
112                    
113                    if (masters.contains(master)) {
114                            return true;
115                    }
116                    
117                    TIntIterator it=masters.iterator();
118                    while (it.hasNext()) {
119                            if (((LoaderEntry) repoLanguage.loadersMap.get(it.next())).dependsOn(master, originalMaster)) {
120                                    return true;
121                            }
122                    }
123                    
124                    return false;
125            }
126            
127            boolean isScanDependent() {
128                    return isScanDependent(null);
129            }
130            
131            /**
132             * @return true if this loader is not dependent of any others
133             */
134            boolean isIndependent() {
135                    return masters.isEmpty();
136            }
137            
138            private boolean isScanDependent(String startingLevel) {
139                    if (getScanDependent()) {
140                            return true;
141                    }
142                    
143                    if (getLevel().equals(startingLevel)) {
144                            throw new CircularReferenceException("Circular reference in loader dependency: "+getLevel());
145                    }
146                    
147                    String actualStartingLevel = startingLevel==null ? getLevel() : startingLevel;
148                    TIntIterator mit=masters.iterator();
149                    while (mit.hasNext()) {
150                            if (((LoaderEntry) repoLanguage.loadersMap.get(mit.next())).isScanDependent(actualStartingLevel)) {
151                                    return true;
152                            }
153                    }
154                    
155                    return false;
156            }
157            
158            /**
159             * @param loadLevels
160             * @return true if all prerequisite levels were loaded
161             * and this level wasn't.
162             */
163            boolean isCompatible(TIntHashSet loadLevels) {
164                    return !loadLevels.contains(getId()) && loadLevels.containsAll(masters.toArray());
165            }
166            
167    }