001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package lucee.intergral.fusiondebug.server;
020
021import java.io.PrintWriter;
022import java.util.ArrayList;
023import java.util.Iterator;
024import java.util.List;
025import java.util.Map;
026import java.util.Map.Entry;
027
028import lucee.commons.io.SystemUtil;
029import lucee.commons.lang.SystemOut;
030import lucee.runtime.CFMLFactory;
031import lucee.runtime.CFMLFactoryImpl;
032import lucee.runtime.Info;
033import lucee.runtime.PageContextImpl;
034import lucee.runtime.config.Config;
035import lucee.runtime.config.ConfigWebImpl;
036import lucee.runtime.engine.CFMLEngineImpl;
037import lucee.runtime.engine.ThreadLocalPageContext;
038import lucee.runtime.op.Caster;
039import lucee.runtime.security.SerialNumber;
040
041import com.intergral.fusiondebug.server.IFDController;
042import com.intergral.fusiondebug.server.IFDThread;
043
044/**
045 * 
046 */
047public class FDControllerImpl implements IFDController {
048
049
050        private List exceptionTypes;
051        private CFMLEngineImpl engine;
052        private boolean isEnterprise;
053        
054        
055        public FDControllerImpl(CFMLEngineImpl engine,String serial){
056                this.isEnterprise=SerialNumber.isEnterprise(serial);
057                this.engine=engine;
058        }
059
060        @Override
061        public String getEngineName() {
062                return "Lucee";
063        }
064
065        @Override
066        public String getEngineVersion() {
067                return Info.getVersionAsString();
068        }
069
070        @Override
071        public List getExceptionTypes() {
072                if(exceptionTypes==null){
073                        exceptionTypes=new ArrayList();
074                        exceptionTypes.add("application");
075                        exceptionTypes.add("expression");
076                        exceptionTypes.add("database");
077                        exceptionTypes.add("custom_type");
078                        exceptionTypes.add("lock");
079                        exceptionTypes.add("missinginclude");
080                        exceptionTypes.add("native");
081                        exceptionTypes.add("security");
082                        exceptionTypes.add("template");
083                }
084                return exceptionTypes;
085        }
086
087        /**
088         * @deprecated use instead <code>{@link #getLicenseInformation(String)}</code>
089         */
090        public String getLicenseInformation() {
091                throw new RuntimeException("please replace your fusiondebug-api-server-1.0.xxx-SNAPSHOT.jar with a newer version");
092        }
093
094        @Override
095        public String getLicenseInformation(String key) {
096                if(!isEnterprise) {
097                        SystemOut.print(new PrintWriter(System.err),"FD Server Licensing does not work with the Open Source Version of Lucee or Enterprise Version of Lucee that is not enabled");
098                        return null;
099                }
100                return FDLicense.getLicenseInformation(key);
101        }
102
103
104        @Override
105        public void output(String message) {
106                Config config = ThreadLocalPageContext.getConfig();
107                PrintWriter out=config==null?SystemUtil.getPrintWriter(SystemUtil.OUT):((ConfigWebImpl)config).getOutWriter();
108                SystemOut.print(out, message);
109        }
110
111        @Override
112        public List pause() {
113                List<IFDThread> threads = new ArrayList<IFDThread>();
114                Iterator<Entry<String, CFMLFactory>> it = engine.getCFMLFactories().entrySet().iterator();
115                Entry<String, CFMLFactory> entry;
116                while(it.hasNext()){
117                        entry = it.next();
118                        pause(entry.getKey(),(CFMLFactoryImpl) entry.getValue(), threads);
119                }
120                
121                return threads;
122        }
123        
124        private void pause(String name,CFMLFactoryImpl factory,List<IFDThread> threads) {
125                Map<Integer, PageContextImpl> pcs = factory.getActivePageContexts();
126                Iterator<PageContextImpl> it = pcs.values().iterator();
127                PageContextImpl pc;
128                
129                while(it.hasNext()){
130                        pc=it.next();
131                        try {
132                                pc.getThread().wait();
133                        } catch (InterruptedException e) {
134                                e.printStackTrace();
135                        }
136                        threads.add(new FDThreadImpl(this,factory,name,pc));
137                }
138        }
139        
140        @Override
141        public boolean getCaughtStatus(
142                        String exceptionType,
143                        String executionUnitName,
144            String executionUnitPackage,
145            String sourceFilePath,
146            String sourceFileName,
147            int lineNumber) {
148                // TODO [007]
149                return true;
150        }
151
152        @Override
153        public IFDThread getByNativeIdentifier(String id) {
154                Iterator<Entry<String, CFMLFactory>> it = engine.getCFMLFactories().entrySet().iterator();
155                Entry<String, CFMLFactory> entry;
156                FDThreadImpl thread;
157                while(it.hasNext()){
158                        entry = it.next();
159                        thread = getByNativeIdentifier( entry.getKey(),(CFMLFactoryImpl) entry.getValue(),id);
160                        if(thread!=null) return thread;
161                }
162                return null;
163        }
164        
165        /**
166         * checks a single CFMLFactory for the thread
167         * @param name
168         * @param factory
169         * @param id
170         * @return matching thread or null
171         */
172        private FDThreadImpl getByNativeIdentifier(String name,CFMLFactoryImpl factory,String id) {
173                Map<Integer, PageContextImpl> pcs = factory.getActivePageContexts();
174                Iterator<PageContextImpl> it = pcs.values().iterator();
175                PageContextImpl pc;
176                
177                while(it.hasNext()){
178                        pc=it.next();
179                        if(equals(pc,id)) return new FDThreadImpl(this,factory,name,pc);
180                }
181                return null;
182        }
183
184        /**
185         * check if thread of PageContext match given id
186         * @param pc
187         * @param id
188         * @return match the id the pagecontext
189         */
190        private boolean equals(PageContextImpl pc, String id) {
191                Thread thread = pc.getThread();
192                if(Caster.toString(FDThreadImpl.id(pc)).equals(id)) return true;
193                if(Caster.toString(thread.getId()).equals(id)) return true;
194                if(Caster.toString(thread.hashCode()).equals(id)) return true;
195                return false;
196        }
197
198        @Override
199        public String getCompletionMethod() {
200                return "serviceCFML";
201        }
202
203        @Override
204        public String getCompletionType() {
205                return CFMLEngineImpl.class.getName();
206        }
207
208        @Override
209        public void release() {
210                this.engine.allowRequestTimeout(true);
211        }
212}