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.runtime.config;
020
021import java.io.ByteArrayInputStream;
022import java.io.File;
023import java.io.IOException;
024import java.io.InputStream;
025import java.io.UnsupportedEncodingException;
026import java.net.MalformedURLException;
027import java.net.URL;
028import java.util.ArrayList;
029import java.util.HashSet;
030import java.util.Iterator;
031import java.util.List;
032import java.util.Map;
033import java.util.Map.Entry;
034import java.util.Set;
035
036import javax.servlet.ServletException;
037
038import lucee.commons.digest.MD5;
039import lucee.commons.io.FileUtil;
040import lucee.commons.io.IOUtil;
041import lucee.commons.io.SystemUtil;
042import lucee.commons.io.cache.Cache;
043import lucee.commons.io.log.log4j.appender.ConsoleAppender;
044import lucee.commons.io.log.log4j.appender.RollingResourceAppender;
045import lucee.commons.io.log.log4j.layout.ClassicLayout;
046import lucee.commons.io.res.Resource;
047import lucee.commons.io.res.ResourceProvider;
048import lucee.commons.io.res.filter.ResourceNameFilter;
049import lucee.commons.io.res.type.s3.S3ResourceProvider;
050import lucee.commons.io.res.util.ResourceUtil;
051import lucee.commons.lang.ClassException;
052import lucee.commons.lang.ClassUtil;
053import lucee.commons.lang.ExceptionUtil;
054import lucee.commons.lang.StringUtil;
055import lucee.commons.lang.SystemOut;
056import lucee.commons.net.HTTPUtil;
057import lucee.commons.net.IPRange;
058import lucee.commons.net.URLEncoder;
059import lucee.commons.net.http.HTTPEngine;
060import lucee.commons.net.http.HTTPResponse;
061import lucee.loader.engine.CFMLEngineFactory;
062import lucee.loader.util.ExtensionFilter;
063import lucee.runtime.Info;
064import lucee.runtime.PageContext;
065import lucee.runtime.cache.CacheConnection;
066import lucee.runtime.cache.eh.EHCache;
067import lucee.runtime.cfx.CFXTagException;
068import lucee.runtime.cfx.CFXTagPool;
069import lucee.runtime.converter.ConverterException;
070import lucee.runtime.converter.WDDXConverter;
071import lucee.runtime.db.DataSource;
072import lucee.runtime.exp.ApplicationException;
073import lucee.runtime.exp.ExpressionException;
074import lucee.runtime.exp.HTTPException;
075import lucee.runtime.exp.PageException;
076import lucee.runtime.exp.SecurityException;
077import lucee.runtime.extension.Extension;
078import lucee.runtime.extension.RHExtension;
079import lucee.runtime.functions.cache.Util;
080import lucee.runtime.functions.other.CreateObject;
081import lucee.runtime.functions.other.CreateUUID;
082import lucee.runtime.functions.other.URLEncodedFormat;
083import lucee.runtime.functions.string.Hash;
084import lucee.runtime.gateway.GatewayEntry;
085import lucee.runtime.gateway.GatewayEntryImpl;
086import lucee.runtime.listener.AppListenerUtil;
087import lucee.runtime.net.ntp.NtpClient;
088import lucee.runtime.op.Caster;
089import lucee.runtime.op.Decision;
090import lucee.runtime.orm.ORMConfiguration;
091import lucee.runtime.orm.ORMConfigurationImpl;
092import lucee.runtime.reflection.Reflector;
093import lucee.runtime.security.SecurityManager;
094import lucee.runtime.security.SecurityManagerImpl;
095import lucee.runtime.security.SerialNumber;
096import lucee.runtime.text.xml.XMLCaster;
097import lucee.runtime.text.xml.XMLUtil;
098import lucee.runtime.type.Array;
099import lucee.runtime.type.ArrayImpl;
100import lucee.runtime.type.Collection.Key;
101import lucee.runtime.type.KeyImpl;
102import lucee.runtime.type.Query;
103import lucee.runtime.type.QueryImpl;
104import lucee.runtime.type.Struct;
105import lucee.runtime.type.dt.TimeSpan;
106import lucee.runtime.type.scope.Cluster;
107import lucee.runtime.type.scope.ClusterNotSupported;
108import lucee.runtime.type.scope.ClusterRemote;
109import lucee.runtime.type.scope.ScopeContext;
110import lucee.runtime.type.util.ArrayUtil;
111import lucee.runtime.type.util.ComponentUtil;
112import lucee.runtime.type.util.ListUtil;
113import lucee.runtime.video.VideoExecuter;
114import lucee.runtime.video.VideoExecuterNotSupported;
115import lucee.transformer.library.function.FunctionLibException;
116import lucee.transformer.library.tag.TagLibException;
117
118import org.apache.log4j.HTMLLayout;
119import org.apache.log4j.Level;
120import org.apache.log4j.PatternLayout;
121import org.apache.log4j.xml.XMLLayout;
122import org.apache.xerces.parsers.DOMParser;
123import org.w3c.dom.DOMException;
124import org.w3c.dom.Document;
125import org.w3c.dom.Element;
126import org.xml.sax.InputSource;
127import org.xml.sax.SAXException;
128
129import com.allaire.cfx.CustomTag;
130
131/**
132 * 
133 */
134public final class ConfigWebAdmin {
135    
136    //private static final Object NULL = new Object();
137        private ConfigImpl config;
138    private Document doc;
139        private String password;
140    //private SecurityManager accessorx;
141
142
143    /**
144     * 
145     * @param config
146     * @param password
147     * @return returns a new instance of the class
148     * @throws SAXException
149     * @throws IOException
150     */
151    public static ConfigWebAdmin newInstance(ConfigImpl config, String password) throws SAXException, IOException {
152        return new ConfigWebAdmin(config, password);
153    }
154    
155
156    private void checkWriteAccess() throws SecurityException {
157        ConfigWebUtil.checkGeneralWriteAccess(config,password);
158        }
159    private void checkReadAccess() throws SecurityException {
160        ConfigWebUtil.checkGeneralReadAccess(config,password);
161        }
162    
163    /**
164     * @param password
165     * @throws IOException 
166     * @throws DOMException 
167     * @throws ExpressionException 
168     */
169    public void setPassword(Password password) throws SecurityException, DOMException, IOException {
170        checkWriteAccess();
171        Password.store(doc.getDocumentElement(), password, false);
172    }
173
174    public void setVersion(double version) {
175        setVersion(doc,version);
176        
177    }
178    public static void setVersion(Document doc,double version) {
179        Element root=doc.getDocumentElement();
180        String str = Caster.toString(version);
181        if(str.length()>3)str=str.substring(0,3);
182        root.setAttribute("version",str); 
183        
184    }
185    /*public void setId(String id) {
186        
187        Element root=doc.getDocumentElement();
188        if(!StringUtil.isEmpty(root.getAttribute("id"))) return;
189        root.setAttribute("id",id); 
190        try {
191                        store(config);
192                } 
193        catch (Exception e) {}
194    }*/
195    
196    /**
197     * @param contextPath
198     * @param password
199     * @throws FunctionLibException
200     * @throws TagLibException
201     * @throws IOException
202     * @throws ClassNotFoundException
203     * @throws SAXException
204     * @throws PageException
205     */
206    public void removePassword(String contextPath) throws PageException, SAXException, ClassException, IOException, TagLibException, FunctionLibException {
207        checkWriteAccess();
208        if(contextPath==null || contextPath.length()==0 || !(config instanceof ConfigServerImpl)) {
209                // config.setPassword(password); do nothing!
210        }
211        else { 
212            ConfigServerImpl cs=(ConfigServerImpl)config;
213            ConfigWebImpl cw=cs.getConfigWebImpl(contextPath);
214            if(cw!=null)cw.updatePassword(false,cw.getPassword(),null);
215        }
216    }
217    
218    private ConfigWebAdmin(ConfigImpl config, String password) throws SAXException, IOException {
219        this.config=config;
220        this.password=password;
221        doc=loadDocument(config.getConfigFile());
222        //setId(config.getId());
223    } 
224    
225    public static void checkForChangesInConfigFile(Config config) {
226        ConfigImpl ci=(ConfigImpl) config;
227                if(!ci.checkForChangesInConfigFile()) return;
228                
229                Resource file = config.getConfigFile();
230                long diff=file.lastModified()-ci.lastModified();
231                if(diff<10 && diff>-10) return; 
232                // reload
233                try {
234                        ConfigWebAdmin admin = ConfigWebAdmin.newInstance(ci, null);
235                        admin.reload(ci, false);
236                        SystemOut.printDate(ci.getOutWriter(), "reloaded the configuration ["+file+"] automaticly");
237                } 
238                catch (Throwable t) {
239                ExceptionUtil.rethrowIfNecessary(t);
240                        t.printStackTrace();
241                }
242        }
243    
244    
245
246    private void addResourceProvider(String scheme,String clazz,String arguments) throws SecurityException {
247        checkWriteAccess();
248        
249        Element resources=_getRootElement("resources");
250        Element[] rpElements = ConfigWebFactory.getChildren(resources,"resource-provider");
251        String s;
252        // update
253        if(rpElements!=null) {
254                for(int i=0;i<rpElements.length;i++) {
255                        s=rpElements[i].getAttribute("scheme");
256                        if(!StringUtil.isEmpty(s) && s.equalsIgnoreCase(scheme))        {
257                                rpElements[i].setAttribute("class", clazz);
258                                rpElements[i].setAttribute("scheme", scheme);
259                                rpElements[i].setAttribute("arguments", arguments);
260                                return;
261                        }
262                }
263        }
264        // Insert
265        Element el=doc.createElement("resource-provider");
266        resources.appendChild(XMLCaster.toRawNode(el));
267        el.setAttribute("class", clazz);
268        el.setAttribute("scheme", scheme);
269        el.setAttribute("arguments", arguments);
270        }
271
272
273        /**
274     * load XML Document from XML File
275     * @param config
276     * @param xmlFile XML File to read
277     * @return returns the Document
278     * @throws SAXException
279     * @throws IOException
280     */
281    private static Document loadDocument(Resource xmlFile) throws SAXException, IOException {
282        DOMParser parser = new DOMParser();
283        InputStream is=null;
284        try {
285                is = IOUtil.toBufferedInputStream(xmlFile.getInputStream());
286            InputSource source = new InputSource(is);
287            parser.parse(source);
288        }
289        finally {
290                IOUtil.closeEL(is);
291        }
292            return parser.getDocument();
293    }
294    
295    private static synchronized void _store(ConfigImpl config) throws PageException, SAXException, ClassException, IOException, TagLibException, FunctionLibException  {
296        ConfigWebAdmin admin = new ConfigWebAdmin(config, null);
297        admin._reload(config, true);
298    }
299
300    private synchronized void _store() throws PageException, SAXException, ClassException, IOException, TagLibException, FunctionLibException  {
301        _reload(config, true);
302    }
303    
304    public synchronized void store() throws PageException, SAXException, ClassException, IOException, TagLibException, FunctionLibException  {
305        reload(config, true);
306    }
307    
308    private synchronized void reload(ConfigImpl config, boolean storeInMemoryData) throws PageException, SAXException, ClassException, IOException, TagLibException, FunctionLibException  {
309        if(storeInMemoryData)checkWriteAccess();
310        _reload(config, storeInMemoryData);
311    }
312
313    private synchronized void _reload(ConfigImpl config, boolean storeInMemoryData) throws PageException, SAXException, ClassException, IOException, TagLibException, FunctionLibException  {
314        renameOldstyleCFX();
315        
316        createAbort();
317        if(config instanceof ConfigServerImpl) {
318                if(storeInMemoryData)XMLCaster.writeTo(doc,config.getConfigFile());
319            
320            ConfigServerImpl cs=(ConfigServerImpl) config;
321            ConfigServerFactory.reloadInstance(cs);
322            ConfigWeb[] webs=cs.getConfigWebs();
323            for(int i=0;i<webs.length;i++) {
324                ConfigWebFactory.reloadInstance((ConfigServerImpl) config,(ConfigWebImpl)webs[i],true);
325            }
326        }
327        else {
328                if(storeInMemoryData)XMLCaster.writeTo(doc,config.getConfigFile());
329            //SystemUtil.sleep(10);
330            ConfigServerImpl cs=((ConfigWebImpl)config).getConfigServerImpl();
331            
332            ConfigWebFactory.reloadInstance(cs,(ConfigWebImpl)config,false);
333        }
334    }
335    
336    
337    
338
339    private void createAbort() {
340        try {
341                ConfigWebFactory.getChildByName(doc.getDocumentElement(),"cfabort",true);
342        }
343        catch(Throwable t) {
344                ExceptionUtil.rethrowIfNecessary(t);
345        }
346    }
347
348
349        public void setTaskMaxThreads(Integer maxThreads) throws SecurityException {
350                checkWriteAccess();
351        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
352        if(!hasAccess)
353            throw new SecurityException("no access to update task settings");
354        Element mail=_getRootElement("remote-clients");
355        mail.setAttribute("max-threads",Caster.toString(maxThreads,""));
356        }
357
358        /**
359     * sets Mail Logger to Config
360     * @param logFile
361     * @param level 
362     * @throws PageException 
363     */
364    public void setMailLog(String logFile, String level) throws PageException {
365        checkWriteAccess();
366        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_MAIL);
367        
368        if(!hasAccess)
369            throw new SecurityException("no access to update mail server settings");
370        ConfigWebUtil.getFile(config,config.getRootDirectory(),logFile,FileUtil.TYPE_FILE);
371        
372        
373        Element logging = ConfigWebFactory.getChildByName(doc.getDocumentElement(), "logging");
374                Element[] children = XMLUtil.getChildElementsAsArray(logging);
375                Element logger=null;
376        
377                for(int i=0;i<children.length;i++){
378                        if(children[i].getTagName().equals("logger") && "mail".equalsIgnoreCase(children[i].getAttribute("name"))) {
379                                logger=children[i];
380                                break;
381                        }
382                }
383                if(logger==null) {
384                        logger = doc.createElement("logger");
385                        logging.appendChild(logger);
386                }
387                logger.setAttribute("name", "mail");
388        if("console".equalsIgnoreCase(logFile)) {
389                logger.setAttribute("appender", "console");
390                logger.setAttribute("layout", "pattern");
391        }
392        else {
393                logger.setAttribute("appender", "resource");
394                logger.setAttribute("appender-arguments", "path:"+logFile);
395                logger.setAttribute("layout", "classic");
396                }
397        logger.setAttribute("log-level",level);
398    }
399
400    /**
401     * sets if spool is enable or not
402     * @param spoolEnable
403     * @throws SecurityException
404     */
405    public void setMailSpoolEnable(Boolean spoolEnable) throws SecurityException {
406        checkWriteAccess();
407        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_MAIL);
408        
409        if(!hasAccess)
410            throw new SecurityException("no access to update mail server settings");
411        Element mail=_getRootElement("mail");
412        mail.setAttribute("spool-enable",Caster.toString(spoolEnable,""));
413        //config.setMailSpoolEnable(spoolEnable);
414    }
415    
416    
417
418    /* *
419     * sets if er interval is enable or not
420     * @param interval
421     * @throws SecurityException
422     * /
423    public void setMailSpoolInterval(Integer interval) throws SecurityException {
424        checkWriteAccess();
425        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_MAIL);
426        if(!hasAccess)
427            throw new SecurityException("no access to update mail server settings");
428        Element mail=_getRootElement("mail");
429        mail.setAttribute("spool-interval",Caster.toString(interval,""));
430        //config.setMailSpoolInterval(interval);
431    }*/
432
433    /**
434     * sets the timeout for the spooler for one job
435     * @param timeout
436     * @throws SecurityException
437     */
438    public void setMailTimeout(Integer timeout) throws SecurityException {
439        checkWriteAccess();
440        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_MAIL);
441        if(!hasAccess)
442            throw new SecurityException("no access to update mail server settings");
443        Element mail=_getRootElement("mail");
444        mail.setAttribute("timeout",Caster.toString(timeout,""));
445        //config.setMailTimeout(timeout);
446    }
447    
448    /**
449     * sets the charset for the mail
450     * @param timeout
451     * @throws SecurityException
452     */
453    public void setMailDefaultCharset(String charset) throws PageException {
454        checkWriteAccess();
455        boolean hasAccess = ConfigWebUtil.hasAccess(config, SecurityManager.TYPE_MAIL);
456        if(!hasAccess) throw new SecurityException("no access to update mail server settings");
457        
458        if(!StringUtil.isEmpty(charset)){
459                        try {
460                                IOUtil.checkEncoding(charset);
461                        } catch (IOException e) {
462                                throw Caster.toPageException(e);
463                        }
464        }
465        
466                Element mail=_getRootElement("mail");
467        mail.setAttribute("default-encoding",charset);
468        //config.setMailDefaultEncoding(charset);               
469        }
470
471        /**
472     * insert or update a mailserver on system
473     * @param hostName
474     * @param username
475     * @param password
476     * @param port
477         * @param ssl 
478         * @param tls 
479     * @throws PageException 
480     */
481    public void updateMailServer(String hostName,String username,String password, int port, boolean tls, boolean ssl,long lifeTimeSpan, long idleTimeSpan) throws PageException {
482        checkWriteAccess();
483        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_MAIL);
484        if(!hasAccess)
485            throw new SecurityException("no access to update mail server settings");
486        
487        /*try {
488            SMTPVerifier.verify(hostName,username,password,port);
489        } catch (SMTPException e) {
490            throw Caster.toPageException(e);
491        }*/
492        
493        Element mail=_getRootElement("mail");
494        if(port<1) port=21;
495
496        if(hostName==null || hostName.trim().length()==0)
497            throw new ExpressionException("Host (SMTP) can be a empty value");
498        hostName=hostName.trim();
499        
500        
501        Element[] children = ConfigWebFactory.getChildren(mail,"server");
502        
503        // Update
504        Element server=null;
505        for(int i=0;i<children.length;i++) {
506            Element el=children[i];
507            String smtp=el.getAttribute("smtp");
508                        if(smtp!=null && smtp.equalsIgnoreCase(hostName)) {
509                        server=el;
510                        break;
511                        }
512        }
513        
514        // Insert
515        if(server==null) {
516                server = doc.createElement("server");
517                mail.appendChild(XMLCaster.toRawNode(server));
518        }
519        server.setAttribute("smtp",hostName);
520        server.setAttribute("username",username);
521        server.setAttribute("password",ConfigWebFactory.encrypt(password));
522        server.setAttribute("port",Caster.toString(port));
523        server.setAttribute("tls",Caster.toString(tls));
524        server.setAttribute("ssl",Caster.toString(ssl));
525        server.setAttribute("life",Caster.toString(lifeTimeSpan));
526        server.setAttribute("idle",Caster.toString(idleTimeSpan));
527        
528    }
529
530    /**
531     *removes a mailserver from system
532     * @param hostName
533     * @throws SecurityException 
534     */
535    public void removeMailServer(String hostName) throws SecurityException {
536        checkWriteAccess();
537        
538        Element mail=_getRootElement("mail");
539        Element[] children = ConfigWebFactory.getChildren(mail,"server");
540        if(children.length>0) {
541                for(int i=0;i<children.length;i++) {
542                    Element el=children[i];
543                    String smtp=el.getAttribute("smtp");
544                                if(smtp!=null && smtp.equalsIgnoreCase(hostName)) {
545                                mail.removeChild(children[i]);
546                                }
547                }
548        }
549    }
550
551        
552        public void removeLogSetting(String name) throws SecurityException {
553                checkWriteAccess();
554        Element logging=_getRootElement("logging");
555        Element[] children = ConfigWebFactory.getChildren(logging,"logger");
556        if(children.length>0) {
557                String _name;
558                for(int i=0;i<children.length;i++) {
559                        Element el=children[i];
560                        _name=el.getAttribute("name");
561                        
562                                if(_name!=null && _name.equalsIgnoreCase(name)) {
563                                        logging.removeChild(children[i]);
564                                }
565                }
566        }
567        }
568    
569    static void updateMapping(ConfigImpl config, String virtual, String physical,String archive,String primary, short inspect, boolean toplevel) throws SAXException, IOException, PageException {
570        ConfigWebAdmin admin = new ConfigWebAdmin(config, null);
571        admin._updateMapping(virtual, physical, archive, primary, inspect, toplevel);
572        admin._store();
573    }
574    
575
576    static void updateComponentMapping(ConfigImpl config, String virtual, String physical,String archive,String primary, short inspect) throws SAXException, IOException, PageException {
577        ConfigWebAdmin admin = new ConfigWebAdmin(config, null);
578        admin._updateComponentMapping(virtual, physical, archive, primary, inspect);
579        admin._store();
580    }
581    
582
583    static void updateCustomTagMapping(ConfigImpl config, String virtual, String physical,String archive,String primary, short inspect) throws SAXException, IOException, PageException {
584        ConfigWebAdmin admin = new ConfigWebAdmin(config, null);
585        admin._updateCustomTag(virtual, physical, archive, primary, inspect);
586        admin._store();
587    }
588
589    /**
590     * insert or update a mapping on system
591     * @param virtual
592     * @param physical
593     * @param archive
594     * @param primary
595     * @param trusted
596     * @param toplevel 
597     * @throws ExpressionException
598     * @throws SecurityException
599     */
600    public void updateMapping(String virtual, String physical,String archive,String primary, short inspect, boolean toplevel) throws ExpressionException, SecurityException {
601        checkWriteAccess();
602        _updateMapping(virtual, physical, archive, primary, inspect, toplevel);
603    }
604    private void _updateMapping(String virtual, String physical,String archive,String primary, short inspect, boolean toplevel) throws ExpressionException, SecurityException {
605        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_MAPPING);
606        
607        virtual=virtual.trim(); 
608        if(physical==null) physical="";
609        else physical=physical.trim();
610        if(archive==null) archive="";
611        else archive=archive.trim();
612        primary=primary.trim();
613        if(!hasAccess)
614            throw new SecurityException("no access to update mappings");
615        
616        // check virtual
617            if(virtual==null || virtual.length()==0)
618                throw new ExpressionException("virtual path cannot be a empty value");
619            virtual=virtual.replace('\\','/');
620            
621            if(!virtual.equals("/") && virtual.endsWith("/"))
622                    virtual=virtual.substring(0,virtual.length()-1);
623            
624            if(virtual.charAt(0)!='/')
625                throw new ExpressionException("virtual path must start with [/]");
626        boolean isArchive=primary.equalsIgnoreCase("archive");
627        
628        if((physical.length()+archive.length())==0)
629            throw new ExpressionException("physical or archive must have a value");
630        
631        if(isArchive && archive.length()==0 ) isArchive=false;
632        //print.ln("isArchive:"+isArchive);
633        
634        if(!isArchive && archive.length()>0 && physical.length()==0 ) isArchive=true;
635        //print.ln("isArchive:"+isArchive);
636        
637        
638        
639        Element mappings=_getRootElement("mappings");
640        // Update
641        Element[] children = ConfigWebFactory.getChildren(mappings,"mapping");
642        for(int i=0;i<children.length;i++) {
643            String v=children[i].getAttribute("virtual");
644            if(v!=null) {
645                if(!v.equals("/") && v.endsWith("/"))
646                    v=v.substring(0,v.length()-1);
647              
648                    if(v.equals(virtual)) {
649                                Element el=children[i];
650                                if(physical.length()>0) {
651                        el.setAttribute("physical",physical);
652                    }
653                    else if(el.hasAttribute("physical")) {
654                        el.removeAttribute("physical");
655                    }
656                                if(archive.length()>0) {
657                        el.setAttribute("archive",archive);
658                    }
659                    else if(el.hasAttribute("archive")) {
660                        el.removeAttribute("archive");
661                    }
662                                el.setAttribute("primary",isArchive?"archive":"physical");
663                                el.setAttribute("inspect-template",ConfigWebUtil.inspectTemplate(inspect, ""));
664                                el.removeAttribute("trusted");
665                                el.setAttribute("toplevel",Caster.toString(toplevel));
666                                return ;
667                                }
668            }
669        }
670        
671        // Insert
672        Element el=doc.createElement("mapping");
673        mappings.appendChild(el);
674        el.setAttribute("virtual",virtual);
675        if(physical.length()>0)el.setAttribute("physical",physical);
676                if(archive.length()>0)el.setAttribute("archive",archive);
677                el.setAttribute("primary",isArchive?"archive":"physical");
678                el.setAttribute("inspect-template",ConfigWebUtil.inspectTemplate(inspect, ""));
679                el.setAttribute("toplevel",Caster.toString(toplevel));
680                
681                // set / to the end
682                children = ConfigWebFactory.getChildren(mappings,"mapping");
683        for(int i=0;i<children.length;i++) {
684            String v=children[i].getAttribute("virtual");
685            
686                if(v!=null && v.equals("/")) {
687                        el=children[i];
688                        mappings.removeChild(el);
689                        mappings.appendChild(el);
690                        return ;
691                        }
692
693        }
694                
695    }
696    
697    public void updateRestMapping(String virtual, String physical,boolean _default) throws ExpressionException, SecurityException {
698        checkWriteAccess();
699        boolean hasAccess=true;// TODO ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_REST);
700        virtual=virtual.trim(); 
701        physical=physical.trim();
702        if(!hasAccess)
703            throw new SecurityException("no access to update REST mapping");
704        
705        // check virtual
706            if(virtual==null || virtual.length()==0)
707                throw new ExpressionException("virtual path cannot be a empty value");
708            virtual=virtual.replace('\\','/');
709            if(virtual.equals("/"))
710                throw new ExpressionException("virtual path cannot be /");
711        
712            
713            if(virtual.endsWith("/"))
714                    virtual=virtual.substring(0,virtual.length()-1);
715            
716            if(virtual.charAt(0)!='/') virtual="/"+virtual;
717        
718        if((physical.length())==0)
719                throw new ExpressionException("physical path cannot be a empty value");
720        
721        Element rest=_getRootElement("rest");
722        Element[] children = ConfigWebFactory.getChildren(rest,"mapping");
723        
724        // remove existing default
725        if(_default) {
726                for(int i=0;i<children.length;i++) {
727                    if(Caster.toBooleanValue(children[i].getAttribute("default"),false))
728                        children[i].setAttribute("default", "false");
729                }
730        }
731        
732        // Update
733        String v;
734        Element el=null;
735        for(int i=0;i<children.length;i++) {
736            v=children[i].getAttribute("virtual");
737            if(v!=null && v.equals(virtual)) {
738                el=children[i];
739            }
740        }
741        
742        
743        // Insert
744        if(el==null) {
745                el=doc.createElement("mapping");
746                rest.appendChild(el);
747        }
748        
749        el.setAttribute("virtual",virtual);
750        el.setAttribute("physical",physical);
751                el.setAttribute("default",Caster.toString(_default));
752                                
753    }
754
755
756    /**
757     * delete a mapping on system
758     * @param virtual
759     * @throws ExpressionException
760     * @throws SecurityException 
761     */
762    public void removeMapping(String virtual) throws ExpressionException, SecurityException {
763        checkWriteAccess();
764        // check parameters
765        if(virtual==null || virtual.length()==0)
766            throw new ExpressionException("virtual path cannot be a empty value");
767        virtual=virtual.replace('\\','/');
768        
769        if(!virtual.equals("/") && virtual.endsWith("/"))
770                    virtual=virtual.substring(0,virtual.length()-1);
771        if(virtual.charAt(0)!='/')
772            throw new ExpressionException("virtual path must start with [/]");
773        
774        
775        Element mappings=_getRootElement("mappings");
776
777        Element[] children = ConfigWebFactory.getChildren(mappings,"mapping");
778        for(int i=0;i<children.length;i++) {
779            String v=children[i].getAttribute("virtual");
780            if(v!=null) {
781                if(!v.equals("/") && v.endsWith("/"))
782                    v=v.substring(0,v.length()-1);
783                        if(v!=null && v.equals(virtual)) {
784                                Element el=children[i];
785                                mappings.removeChild(el);
786                                }
787            }
788        }
789    }
790    
791
792    public void removeRestMapping(String virtual) throws ExpressionException, SecurityException {
793        checkWriteAccess();
794        // check parameters
795        if(virtual==null || virtual.length()==0)
796            throw new ExpressionException("virtual path cannot be a empty value");
797        virtual=virtual.replace('\\','/');
798        if(virtual.equals("/"))
799            throw new ExpressionException("virtual path cannot be /");
800        
801        if(virtual.endsWith("/")) virtual=virtual.substring(0,virtual.length()-1);
802        if(virtual.charAt(0)!='/') virtual="/"+virtual;
803        
804        
805        
806        Element mappings=_getRootElement("rest");
807
808        Element[] children = ConfigWebFactory.getChildren(mappings,"mapping");
809        for(int i=0;i<children.length;i++) {
810            String v=children[i].getAttribute("virtual");
811            if(v!=null) {
812                if(!v.equals("/") && v.endsWith("/"))
813                    v=v.substring(0,v.length()-1);
814                        if(v!=null && v.equals(virtual)) {
815                                Element el=children[i];
816                                mappings.removeChild(el);
817                                }
818            }
819        }
820    }
821
822    /**
823     * delete a customtagmapping on system
824     * @param virtual
825     * @throws SecurityException 
826     */
827    public void removeCustomTag(String virtual) throws SecurityException {
828        checkWriteAccess();
829        
830        Element mappings=_getRootElement("custom-tag");
831        Element[] children = ConfigWebFactory.getChildren(mappings,"mapping");
832        for(int i=0;i<children.length;i++) {
833            if(virtual.equals(createVirtual(children[i])))mappings.removeChild(children[i]);
834        }
835    }
836    
837    public void removeComponentMapping(String virtual) throws SecurityException {
838        checkWriteAccess();
839        
840        Element mappings=_getRootElement("component");
841        Element[] children = ConfigWebFactory.getChildren(mappings,"mapping");
842        String v;
843        for(int i=0;i<children.length;i++) {
844                v=createVirtual(children[i]);
845                if(virtual.equals(v))mappings.removeChild(children[i]);
846        }
847    }
848    
849    
850
851
852    /**
853     * insert or update a mapping for Custom Tag
854     * @param virtual
855     * @param physical
856     * @param archive
857     * @param primary
858     * @param trusted
859     * @throws ExpressionException
860     * @throws SecurityException
861     */
862    public void updateCustomTag(String virtual,String physical,String archive,String primary, short inspect) throws ExpressionException, SecurityException {
863        checkWriteAccess();
864        _updateCustomTag(virtual, physical, archive, primary, inspect);
865    }
866    private void _updateCustomTag(String virtual,String physical,String archive,String primary, short inspect) throws ExpressionException, SecurityException {
867        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_CUSTOM_TAG);
868        if(!hasAccess)
869            throw new SecurityException("no access to change custom tag settings");
870        if(physical==null)physical="";
871        if(archive==null)archive="";
872        
873        //virtual="/custom-tag";
874        if(StringUtil.isEmpty(virtual))virtual=createVirtual(physical,archive);
875        
876        boolean isArchive=primary.equalsIgnoreCase("archive");
877        if(isArchive && archive.length()==0 ) {
878            throw new ExpressionException("archive must have a value when primary has value archive");
879        }
880        if(!isArchive && physical.length()==0 ) {
881            throw new ExpressionException("physical must have a value when primary has value physical");
882        }
883        
884        Element mappings=_getRootElement("custom-tag");
885        
886        // Update
887        String v;
888        Element[] children = ConfigWebFactory.getChildren(mappings,"mapping");
889        for(int i=0;i<children.length;i++) {
890                Element el=children[i];
891                v=createVirtual(el);
892                if(v.equals(virtual)) {
893                        el.setAttribute("virtual",v);
894                        el.setAttribute("physical",physical);
895                        el.setAttribute("archive",archive);
896                        el.setAttribute("primary",primary.equalsIgnoreCase("archive")?"archive":"physical");
897                        el.setAttribute("inspect-template",ConfigWebUtil.inspectTemplate(inspect, ""));
898                        el.removeAttribute("trusted");
899                        return ;
900                        }
901        }
902        
903        // Insert
904        Element el=doc.createElement("mapping");
905        mappings.appendChild(el);
906        if(physical.length()>0)el.setAttribute("physical",physical);
907                if(archive.length()>0)el.setAttribute("archive",archive);
908                el.setAttribute("primary",primary.equalsIgnoreCase("archive")?"archive":"physical");
909                el.setAttribute("inspect-template",ConfigWebUtil.inspectTemplate(inspect, ""));
910                el.setAttribute("virtual",virtual);
911    }
912    
913    public void updateComponentMapping(String virtual,String physical,String archive,String primary, short inspect) throws ExpressionException, SecurityException {
914        checkWriteAccess();
915        _updateComponentMapping(virtual, physical, archive, primary, inspect);
916    }   
917    private void _updateComponentMapping(String virtual,String physical,String archive,String primary, short inspect) throws ExpressionException {
918        primary=primary.equalsIgnoreCase("archive")?"archive":"physical";
919        if(physical==null)physical="";
920        else physical=physical.trim();
921        
922        if(archive==null)archive="";
923        else archive=archive.trim();
924        
925        boolean isArchive=primary.equalsIgnoreCase("archive");
926        if(isArchive && archive.length()==0 ) {
927            throw new ExpressionException("archive must have a value when primary has value archive");
928        }
929        if(!isArchive && physical.length()==0 ) {
930            throw new ExpressionException("physical must have a value when primary has value physical");
931        }
932        
933        Element mappings=_getRootElement("component");
934        Element[] children = ConfigWebFactory.getChildren(mappings,"mapping");
935        Element el;
936        
937        /* ignore when exists
938        for(int i=0;i<children.length;i++) {
939                el=children[i];
940            if(el.getAttribute("physical").equals(physical) &&
941                        el.getAttribute("archive").equals(archive) &&
942                        el.getAttribute("primary").equals(primary) &&
943                        el.getAttribute("trusted").equals(Caster.toString(trusted))){
944                return;
945                        }
946        }*/
947        
948        
949        // Update
950        String v;
951        for(int i=0;i<children.length;i++) {
952                el=children[i];
953                v=createVirtual(el); // if there is no virtual defintion (old records), we use the position
954                if(v.equals(virtual)) {
955                        el.setAttribute("virtual",v); // set to make sure it exists for the future
956                        el.setAttribute("physical",physical);
957                        el.setAttribute("archive",archive);
958                        el.setAttribute("primary",primary.equalsIgnoreCase("archive")?"archive":"physical");
959                        el.setAttribute("inspect-template",ConfigWebUtil.inspectTemplate(inspect, ""));
960                        el.removeAttribute("trusted");
961                        return ;
962                        }
963        }
964        
965        // Insert
966        el=doc.createElement("mapping");
967        mappings.appendChild(el);
968        if(physical.length()>0)el.setAttribute("physical",physical);
969                if(archive.length()>0)el.setAttribute("archive",archive);
970                el.setAttribute("primary",primary.equalsIgnoreCase("archive")?"archive":"physical");
971                el.setAttribute("inspect-template",ConfigWebUtil.inspectTemplate(inspect, ""));
972                el.setAttribute("virtual",virtual);
973    }
974
975    
976
977
978    public static String createVirtual(Element el) {
979        String str = el.getAttribute("virtual");
980        if(!StringUtil.isEmpty(str)) return str;
981        
982        return  createVirtual(el.getAttribute("physical"),el.getAttribute("archive"));
983        }
984    public static String createVirtual(String physical,String archive) {
985        return  "/"+MD5.getDigestAsString(physical+":"+archive,"");
986        }
987
988
989        /**
990     * insert or update a Java CFX Tag
991     * @param name
992     * @param strClass
993     * @throws PageException 
994     */
995    public void updateJavaCFX(String name,String strClass) throws PageException {
996        checkWriteAccess();
997        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_CFX_SETTING);
998        
999        if(!hasAccess) throw new SecurityException("no access to change cfx settings");
1000        
1001        
1002        try {
1003                Class clazz = ClassUtil.loadClass(config.getClassLoader(),strClass);
1004                        if(!Reflector.isInstaneOf(clazz, CustomTag.class))
1005                                throw new ExpressionException("class ["+strClass+"] must implement interface ["+CustomTag.class.getName()+"]");
1006           
1007        } 
1008        catch (ClassException e) {
1009                
1010                throw Caster.toPageException(e);
1011                }
1012        
1013        
1014        
1015        
1016        if(name==null || name.length()==0)
1017            throw new ExpressionException("class name can't be a empty value");
1018        
1019        renameOldstyleCFX();
1020        
1021        
1022        Element tags=_getRootElement("ext-tags");
1023        
1024        // Update
1025        Element[] children = ConfigWebFactory.getChildren(tags,"ext-tag");
1026        for(int i=0;i<children.length;i++) {
1027            String n=children[i].getAttribute("name");
1028            
1029            if(n!=null && n.equalsIgnoreCase(name)) {
1030                        Element el=children[i];
1031                        if(!"java".equalsIgnoreCase(el.getAttribute("type"))) throw new ExpressionException("there is already a c++ cfx tag with this name");
1032                el.setAttribute("class",strClass);
1033                        el.setAttribute("type","java");
1034                        return ;
1035                        }
1036            
1037        }
1038        
1039        // Insert
1040        Element el=doc.createElement("ext-tag");
1041        tags.appendChild(el);
1042        el.setAttribute("class",strClass);
1043        el.setAttribute("name",name);
1044                el.setAttribute("type","java");                 
1045    }
1046    
1047    public void updateCPPCFX(String name, String procedure, String strServerLibrary, boolean keepAlive) throws PageException {
1048        checkWriteAccess();
1049        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_CFX_SETTING);
1050        
1051        if(!hasAccess) throw new SecurityException("no access to change cfx settings");
1052        
1053        // name
1054        if(StringUtil.isEmpty(name))
1055            throw new ExpressionException("name cannot be a empty value");
1056        
1057        // serverLibrary
1058        if(StringUtil.isEmpty(strServerLibrary)) throw new ExpressionException("serverLibrary cannot be a empty value");
1059        Resource serverLibrary = ResourceUtil.toResourceExisting(config, strServerLibrary);
1060        
1061        // procedure
1062        if(StringUtil.isEmpty(procedure)) throw new ExpressionException("procedure cannot be a empty value");
1063        
1064        renameOldstyleCFX();
1065        
1066        
1067        Element tags=_getRootElement("ext-tags");
1068        
1069        // Update
1070        Element[] children = ConfigWebFactory.getChildren(tags,"ext-tag");
1071        for(int i=0;i<children.length;i++) {
1072            String n=children[i].getAttribute("name");
1073            
1074            if(n!=null && n.equalsIgnoreCase(name)) {
1075                        Element el=children[i];
1076                        if(!"cpp".equalsIgnoreCase(el.getAttribute("type"))) throw new ExpressionException("there is already a java cfx tag with this name");
1077                el.setAttribute("server-library",serverLibrary.getAbsolutePath());
1078                el.setAttribute("procedure",procedure);
1079                el.setAttribute("keep-alive",Caster.toString(keepAlive));
1080                el.setAttribute("type","cpp");
1081                        return ;
1082                        }
1083            
1084        }
1085        
1086        // Insert
1087        Element el=doc.createElement("ext-tag");
1088        tags.appendChild(el);
1089        el.setAttribute("server-library",serverLibrary.getAbsolutePath());
1090        el.setAttribute("procedure",procedure);
1091        el.setAttribute("keep-alive",Caster.toString(keepAlive));
1092        el.setAttribute("name",name);
1093                el.setAttribute("type","cpp"); 
1094        }
1095    
1096    private void renameOldstyleCFX() {
1097        
1098        Element tags=_getRootElement("ext-tags",false,true);
1099        if(tags!=null) return;
1100        tags=_getRootElement("cfx-tags",false,true);
1101        if(tags==null) return;
1102        
1103        
1104        
1105        Element newTags = _getRootElement("ext-tags");
1106        Element[] children = ConfigWebFactory.getChildren(tags,"cfx-tag");
1107        String type;
1108        // copy
1109        for(int i=0;i<children.length;i++) {
1110            Element el=doc.createElement("ext-tag");
1111            newTags.appendChild(el);
1112            type=children[i].getAttribute("type");
1113            // java
1114            if(type.equalsIgnoreCase("java")){
1115                el.setAttribute("class",children[i].getAttribute("class"));
1116            }
1117            // c++
1118            else {
1119                el.setAttribute("server-library",children[i].getAttribute("server-library"));
1120                el.setAttribute("procedure",children[i].getAttribute("procedure"));
1121                el.setAttribute("keep-alive",children[i].getAttribute("keep-alive"));
1122                
1123            }
1124                el.setAttribute("name",children[i].getAttribute("name"));
1125                el.setAttribute("type",children[i].getAttribute("type"));  
1126        }
1127        
1128        // remove old
1129        for(int i=0;i<children.length;i++) {
1130                tags.removeChild(children[i]);
1131        }
1132        tags.getParentNode().removeChild(tags);
1133        }
1134    
1135
1136    public static boolean fixLFI(Document doc) {
1137        return "lucee-configuration".equals(doc.getDocumentElement().getNodeName());
1138        
1139    }
1140    
1141    /**
1142     * make sure every context has a salt
1143     * */
1144    public static boolean fixSalt(Document doc) {
1145        Element root=doc.getDocumentElement();
1146        String salt=root.getAttribute("salt");
1147        if(StringUtil.isEmpty(salt,true) || !Decision.isUUId(salt)) {
1148                //create salt
1149                root.setAttribute("salt",CreateUUID.invoke());
1150                return true;
1151        }
1152        return false;
1153    }
1154    
1155    public static boolean fixPSQ(Document doc) {
1156        
1157        Element datasources=ConfigWebFactory.getChildByName(doc.getDocumentElement(),"data-sources",false,true);
1158        if(datasources!=null && datasources.hasAttribute("preserve-single-quote")){
1159                Boolean b=Caster.toBoolean(datasources.getAttribute("preserve-single-quote"),null);
1160                if(b!=null)datasources.setAttribute("psq",Caster.toString(!b.booleanValue()));
1161                datasources.removeAttribute("preserve-single-quote");
1162                return true;
1163        }
1164        return false;
1165    }
1166    
1167
1168    /**
1169     * the following code remove all logging defintions spread over the complete xml and adds them to the new "logging" tag
1170     * 
1171     * @param doc
1172     * @return
1173     */
1174
1175    public static boolean fixLogging(ConfigServerImpl cs,ConfigImpl config,Document doc) {
1176        
1177        if(config.setVersion(doc)>=4.3D) return false;
1178        
1179        // datasource
1180        Element src = ConfigWebFactory.getChildByName(doc.getDocumentElement(), "datasource");
1181        fixLogging(cs,doc,src, "datasource",false,"{lucee-config}/logs/datasource.log");
1182        
1183        
1184        setVersion(doc,Caster.toDoubleValue(Info.getVersionAsString().substring(0,3),4.3D));
1185        
1186        
1187        if(config.setVersion(doc)>=4.2D) return true;
1188        
1189        
1190        //setVersion(Caster.toDoubleValue(Info.getVersionAsString().substring(0,3),1.0D));
1191        
1192        
1193        // mapping
1194        src = ConfigWebFactory.getChildByName(doc.getDocumentElement(), "mappings");
1195        fixLogging(cs,doc,src, "mapping",false,"{lucee-config}/logs/mapping.log");
1196        
1197        // rest
1198        src = ConfigWebFactory.getChildByName(doc.getDocumentElement(), "rest");
1199        fixLogging(cs,doc,src, "rest",false,"{lucee-config}/logs/rest.log");
1200        
1201        // gateway
1202        src = ConfigWebFactory.getChildByName(doc.getDocumentElement(), "gateways");
1203        fixLogging(cs,doc,src, "gateway",false,"{lucee-config}/logs/gateway.log");
1204        
1205        // remote clients
1206        src = ConfigWebFactory.getChildByName(doc.getDocumentElement(), "remote-clients");
1207        fixLogging(cs,doc,src, "remoteclient",false,"{lucee-config}/logs/remoteclient.log");
1208        
1209        // orm
1210        src = ConfigWebFactory.getChildByName(doc.getDocumentElement(), "orm");
1211        fixLogging(cs,doc,src, "orm",false,"{lucee-config}/logs/orm.log");
1212        
1213        // mail
1214        src = ConfigWebFactory.getChildByName(doc.getDocumentElement(), "mail");
1215        fixLogging(cs,doc,src, "mail",false,"{lucee-config}/logs/mail.log");
1216                        
1217                // search
1218        src = ConfigWebFactory.getChildByName(doc.getDocumentElement(), "search");
1219        fixLogging(cs,doc,src, "search",false,"{lucee-config}/logs/search.log");
1220        
1221        // scheduler
1222        src = ConfigWebFactory.getChildByName(doc.getDocumentElement(), "scheduler");
1223        fixLogging(cs,doc,src, "scheduler",false,"{lucee-config}/logs/scheduler.log");
1224        
1225                // scope
1226        src = ConfigWebFactory.getChildByName(doc.getDocumentElement(), "scope");
1227        fixLogging(cs,doc,src, "scope",false,"{lucee-config}/logs/scope.log");
1228        
1229        // application
1230        Element app = src = ConfigWebFactory.getChildByName(doc.getDocumentElement(), "application");
1231        fixLogging(cs,doc,src, "application","application-log","application-log-level",false,"{lucee-config}/logs/application.log");
1232        
1233        // exception
1234        fixLogging(cs,doc,app, "exception","exception-log","exception-log-level",false,"{lucee-config}/logs/exception.log");
1235        
1236        // trace
1237        fixLogging(cs,doc,app, "trace","trace-log","trace-log-level",false,"{lucee-config}/logs/trace.log");
1238        
1239        // thread
1240        fixLogging(cs,doc,app, "thread","thread-log","thread-log-level",false,"{lucee-config}/logs/thread.log");
1241        
1242        // deploy
1243        fixLogging(cs,doc,app, "deploy","deploy-log","deploy-log-level",false,"{lucee-config}/logs/deploy.log");
1244        
1245        // requesttimeout
1246        fixLogging(cs,doc,app, "requesttimeout","requesttimeout-log","requesttimeout-log-level",false,"{lucee-config}/logs/requesttimeout.log");
1247        
1248        setVersion(doc,Caster.toDoubleValue(Info.getVersionAsString().substring(0,3),4.3D));
1249        
1250        
1251        return true;
1252    }
1253
1254    private static boolean fixLogging(ConfigServerImpl cs, Document doc,Element src, String name,boolean deleteSourceAttributes, String defaultValue) {
1255        return fixLogging(cs, doc, src, name, "log", "log-level", deleteSourceAttributes, defaultValue);
1256    }
1257    private static boolean fixLogging(ConfigServerImpl cs, Document doc,Element src, String name,String logName, String levelName,boolean deleteSourceAttributes, String defaultValue) {
1258        
1259        
1260        String path,level;
1261        // Mapping logging
1262        
1263        path = src.getAttribute(logName);
1264        level = src.getAttribute(levelName);
1265        
1266        if(StringUtil.isEmpty(path) && !StringUtil.isEmpty(defaultValue) && (cs==null || cs.getLog(name)==null)) {
1267                // ignore defaultValue, when there is a setting in server context
1268                path=defaultValue;
1269        }
1270        if(!StringUtil.isEmpty(path)) {
1271                if(deleteSourceAttributes)src.removeAttribute(logName);
1272                if(deleteSourceAttributes)src.removeAttribute(levelName);
1273                
1274                Element logging = ConfigWebFactory.getChildByName(doc.getDocumentElement(), "logging");
1275                
1276                // first of all we have to make sure this is not already existing, if it does we ignore the old settings
1277                Element[] children = XMLUtil.getChildElementsAsArray(logging);
1278                for(int i=0;i<children.length;i++){
1279                        if(children[i].getTagName().equals("logger") && name.equalsIgnoreCase(children[i].getAttribute("name"))) {
1280                                return false;
1281                        }
1282                }
1283                
1284                SystemOut.printDate("move "+name+" logging");
1285                Element logger = doc.createElement("logger");
1286                logger.setAttribute("name", name);
1287                if("console".equalsIgnoreCase(path)) {
1288                        logger.setAttribute("appender", "console");
1289                        logger.setAttribute("layout", "pattern");
1290                }
1291                else {
1292                        logger.setAttribute("appender", "resource");
1293                        logger.setAttribute("appender-arguments", "path:"+path);
1294                        logger.setAttribute("layout", "classic");
1295                }
1296                
1297                if(!StringUtil.isEmpty(level,true))logger.setAttribute("level", level.trim());
1298
1299                logging.appendChild(logger);
1300                
1301                return true;
1302        }
1303        return false;
1304    }
1305
1306
1307    public static boolean fixS3(Document doc) {
1308        Element resources=ConfigWebFactory.getChildByName(doc.getDocumentElement(),"resources",false,true);
1309        
1310        Element[] providers = ConfigWebFactory.getChildren(resources,"resource-provider");
1311        
1312        // replace extension class with core class
1313        for(int i=0;i<providers.length;i++) {
1314                if("s3".equalsIgnoreCase(providers[i].getAttribute("scheme"))) {
1315                        if("lucee.extension.io.resource.type.s3.S3ResourceProvider".equalsIgnoreCase(providers[i].getAttribute("class"))){
1316                                providers[i].setAttribute("class", S3ResourceProvider.class.getName());
1317                                return true;
1318                        }
1319                        return false;
1320                }
1321        }
1322        
1323        
1324        // FUTURE remove this part in upcoming versions
1325        // add s3 when not
1326        Element el=doc.createElement("resource-provider");
1327        el.setAttribute("scheme", "s3");
1328        el.setAttribute("class", S3ResourceProvider.class.getName());
1329        el.setAttribute("arguments", "lock-timeout:10000;");
1330        resources.appendChild(el);
1331        
1332        return true;
1333        }
1334
1335    
1336    
1337  
1338    public void verifyCFX(String name) throws PageException {
1339        CFXTagPool pool=config.getCFXTagPool();
1340                CustomTag ct=null;
1341                try {
1342                        ct = pool.getCustomTag(name);
1343                } 
1344        catch (CFXTagException e) {
1345                        throw Caster.toPageException(e);
1346                }
1347        finally {
1348                if(ct!=null)pool.releaseCustomTag(ct);
1349        }
1350                
1351        }
1352    
1353
1354
1355        public void verifyJavaCFX(String name,String strClass) throws PageException {
1356        try {
1357                Class clazz = ClassUtil.loadClass(config.getClassLoader(),strClass);
1358                        if(!Reflector.isInstaneOf(clazz, CustomTag.class))
1359                                throw new ExpressionException("class ["+strClass+"] must implement interface ["+CustomTag.class.getName()+"]");
1360        } 
1361        catch (ClassException e) {
1362                throw Caster.toPageException(e);
1363                }
1364        
1365        if(StringUtil.startsWithIgnoreCase(name,"cfx_"))name=name.substring(4);
1366        if(StringUtil.isEmpty(name))
1367            throw new ExpressionException("class name can't be a empty value");
1368    }
1369    
1370
1371    /**
1372     * remove a CFX Tag
1373     * @param name
1374     * @throws ExpressionException
1375     * @throws SecurityException 
1376     */
1377    public void removeCFX(String name) throws ExpressionException, SecurityException {
1378        checkWriteAccess();
1379        // check parameters
1380        if(name==null || name.length()==0)
1381            throw new ExpressionException("name for CFX Tag can be a empty value");
1382        
1383        renameOldstyleCFX();
1384        
1385        Element mappings=_getRootElement("ext-tags");
1386
1387        Element[] children = ConfigWebFactory.getChildren(mappings,"ext-tag");
1388        for(int i=0;i<children.length;i++) {
1389            String n=children[i].getAttribute("name"); 
1390                if(n!=null && n.equalsIgnoreCase(name)) {
1391                        mappings.removeChild(children[i]);
1392                        }
1393            }
1394    }
1395
1396    /**
1397     * update or insert new database connection
1398     * @param name
1399     * @param clazzName
1400     * @param dsn
1401     * @param username
1402     * @param password
1403     * @param host 
1404     * @param database 
1405     * @param port 
1406     * @param connectionLimit 
1407     * @param connectionTimeout 
1408     * @param blob 
1409     * @param clob 
1410     * @param allow 
1411     * @param storage 
1412     * @param custom 
1413     * @param literalTimestampWithTSOffset 
1414     * @throws ExpressionException
1415     * @throws SecurityException
1416     */
1417    public void updateDataSource(String name, String newName, String clazzName, String dsn, String username, String password,
1418            String host, String database, int port, int connectionLimit, int connectionTimeout, long metaCacheTimeout,
1419            boolean blob, boolean clob, int allow, boolean validate, boolean storage, String timezone, Struct custom, String dbdriver, boolean literalTimestampWithTSOffset) throws ExpressionException, SecurityException {
1420
1421        checkWriteAccess();
1422        SecurityManager sm = config.getSecurityManager();
1423        short access = sm.getAccess(SecurityManager.TYPE_DATASOURCE);
1424        boolean hasAccess=true;
1425        boolean hasInsertAccess=true;
1426        int maxLength=0;
1427        
1428        if(access==SecurityManager.VALUE_YES) hasAccess=true;
1429        else if(access==SecurityManager.VALUE_NO) hasAccess=false;
1430        else if(access>=SecurityManager.VALUE_1 && access<=SecurityManager.VALUE_10){
1431                int existingLength=getDatasourceLength(config);
1432                maxLength=access-SecurityManager.NUMBER_OFFSET;
1433                hasInsertAccess=maxLength>existingLength;
1434                //print.ln("maxLength:"+maxLength);
1435                //print.ln("existingLength:"+existingLength);
1436        }
1437        //print.ln("hasAccess:"+hasAccess);
1438        //print.ln("hasInsertAccess:"+hasInsertAccess);
1439        
1440        //boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_DATASOURCE);
1441        if(!hasAccess)
1442            throw new SecurityException("no access to update datsource connections");
1443        
1444        // check parameters
1445        if(name==null || name.length()==0)
1446            throw new ExpressionException("name can't be a empty value");
1447        
1448        try {
1449                        ClassUtil.loadInstance(clazzName);
1450                }
1451        catch (ClassException e) {
1452            throw new ExpressionException(e.getMessage());
1453                }
1454        
1455        Element datasources=_getRootElement("data-sources");
1456        
1457        // Update
1458        Element[] children = ConfigWebFactory.getChildren(datasources,"data-source");
1459        for(int i=0;i<children.length;i++) {
1460            String n=children[i].getAttribute("name");
1461            
1462            if(n.equalsIgnoreCase(name)) {
1463                        Element el=children[i];
1464                        if(password.equalsIgnoreCase("****************"))
1465                        password=el.getAttribute("password");
1466                    
1467                        if(!StringUtil.isEmpty(newName) && !newName.equals(name))
1468                                el.setAttribute("name",newName);
1469                        el.setAttribute("class",clazzName);
1470                        el.setAttribute("dsn",dsn);
1471                        el.setAttribute("username",username);
1472                        el.setAttribute("password",ConfigWebFactory.encrypt(password));
1473
1474                el.setAttribute("host",host);
1475                if(!StringUtil.isEmpty(timezone))el.setAttribute("timezone",timezone);
1476                else if(el.hasAttribute("timezone")) el.removeAttribute("timezone");
1477                el.setAttribute("database",database);
1478                el.setAttribute("port",Caster.toString(port));
1479                el.setAttribute("connectionLimit",Caster.toString(connectionLimit));
1480                el.setAttribute("connectionTimeout",Caster.toString(connectionTimeout));
1481                el.setAttribute("metaCacheTimeout",Caster.toString(metaCacheTimeout));
1482                el.setAttribute("blob",Caster.toString(blob));
1483                el.setAttribute("clob",Caster.toString(clob));
1484                el.setAttribute("allow",Caster.toString(allow));
1485                el.setAttribute("validate",Caster.toString(validate));
1486                el.setAttribute("storage",Caster.toString(storage));
1487                el.setAttribute("custom",toStringURLStyle(custom));
1488
1489                if (!StringUtil.isEmpty( dbdriver ))
1490                            el.setAttribute("dbdriver", Caster.toString(dbdriver));
1491                
1492                if (literalTimestampWithTSOffset)
1493                            el.setAttribute("literal-timestamp-with-tsoffset", Caster.toString(literalTimestampWithTSOffset));
1494                else 
1495                        el.removeAttribute("literal-timestamp-with-tsoffset");
1496                        return;
1497                        }
1498        }
1499        
1500        if(!hasInsertAccess)
1501            throw new SecurityException("no access to add datasource connections, the maximum count of ["+maxLength+"] datasources is reached");
1502        
1503        // Insert
1504        Element el=doc.createElement("data-source");
1505        datasources.appendChild(el);
1506        if(!StringUtil.isEmpty(newName))
1507                el.setAttribute("name",newName);
1508        else 
1509                el.setAttribute("name",name);
1510                el.setAttribute("class",clazzName);
1511                el.setAttribute("dsn",dsn);
1512                if(username.length()>0)el.setAttribute("username",username);
1513                if(password.length()>0)el.setAttribute("password",ConfigWebFactory.encrypt(password));
1514        
1515        el.setAttribute("host",host);
1516        if(!StringUtil.isEmpty(timezone))el.setAttribute("timezone",timezone);
1517        el.setAttribute("database",database);
1518        if(port>-1)el.setAttribute("port",Caster.toString(port));
1519        if(connectionLimit>-1)el.setAttribute("connectionLimit",Caster.toString(connectionLimit));
1520        if(connectionTimeout>-1)el.setAttribute("connectionTimeout",Caster.toString(connectionTimeout));
1521        if(metaCacheTimeout>-1)el.setAttribute("metaCacheTimeout",Caster.toString(metaCacheTimeout));
1522        
1523        el.setAttribute("blob",Caster.toString(blob));
1524        el.setAttribute("clob",Caster.toString(clob));
1525        el.setAttribute("validate",Caster.toString(validate));
1526        el.setAttribute("storage",Caster.toString(storage));
1527        if(allow>-1)el.setAttribute("allow",Caster.toString(allow));
1528        el.setAttribute("custom",toStringURLStyle(custom));
1529
1530            if (!StringUtil.isEmpty( dbdriver ))
1531                    el.setAttribute("dbdriver", Caster.toString(dbdriver));
1532            
1533            if (literalTimestampWithTSOffset)
1534            el.setAttribute("literal-timestamp-with-tsoffset", Caster.toString(literalTimestampWithTSOffset));
1535        
1536        /*
1537                    String host,String database,int port,String connectionLimit, String connectionTimeout,
1538            boolean blob,boolean clob,int allow,Struct custom
1539        );
1540        */
1541    }
1542    
1543
1544        public void updateGatewayEntry(String id,String className, String cfcPath, String listenerCfcPath,int startupMode,Struct custom, boolean readOnly) throws PageException {
1545                
1546                checkWriteAccess();
1547        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManagerImpl.TYPE_GATEWAY);
1548        
1549        if(!hasAccess)
1550            throw new SecurityException("no access to update gateway entry");
1551        
1552        
1553        // check parameters
1554        id=id.trim();
1555        if(StringUtil.isEmpty(id))
1556            throw new ExpressionException("id can't be a empty value");
1557        
1558        if(StringUtil.isEmpty(className) && StringUtil.isEmpty(cfcPath))
1559                throw new ExpressionException("you must define className or cfcPath");
1560        
1561        try {
1562                if(!StringUtil.isEmpty(className)){
1563                        ClassUtil.loadClass(className);
1564                }
1565                }
1566        catch (ClassException e) {
1567            throw new ExpressionException(e.getMessage());
1568                }
1569        
1570        Element parent=_getRootElement("gateways");
1571        
1572        // Update
1573        Element[] children = ConfigWebFactory.getChildren(parent,"gateway");
1574        for(int i=0;i<children.length;i++) {
1575            String n=children[i].getAttribute("id");
1576            Element el=children[i];
1577            if(n.equalsIgnoreCase(id)) {
1578                el.setAttribute("class",className);
1579                el.setAttribute("cfc-path",cfcPath);
1580                el.setAttribute("listener-cfc-path",listenerCfcPath);
1581                el.setAttribute("startup-mode",GatewayEntryImpl.toStartup(startupMode, "automatic"));
1582                el.setAttribute("custom",toStringURLStyle(custom));
1583                        el.setAttribute("read-only",Caster.toString(readOnly));
1584                        return;
1585                        }
1586          
1587        }
1588        // Insert
1589        Element el=doc.createElement("gateway");
1590        parent.appendChild(el);
1591        el.setAttribute("id",id);
1592        el.setAttribute("cfc-path",cfcPath);
1593        el.setAttribute("listener-cfc-path",listenerCfcPath);
1594            el.setAttribute("startup-mode",GatewayEntryImpl.toStartup(startupMode, "automatic"));
1595            el.setAttribute("class",className);
1596                el.setAttribute("custom",toStringURLStyle(custom));
1597                el.setAttribute("read-only",Caster.toString(readOnly));
1598        
1599    }
1600
1601        public void updateCacheConnection(String name, String classname,int _default, Struct custom,boolean readOnly,boolean storage) throws PageException {
1602        
1603                checkWriteAccess();
1604        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManagerImpl.TYPE_CACHE);
1605                if(!hasAccess)
1606            throw new SecurityException("no access to update cache connection");
1607        
1608        
1609        // check parameters
1610        name=name.trim();
1611        if(StringUtil.isEmpty(name))
1612            throw new ExpressionException("name can't be a empty value");
1613        //else if(name.equals("template") || name.equals("object"))
1614                //throw new ExpressionException("name ["+name+"] is not allowed for a cache connection, the following names are reserved words [object,template]");     
1615        
1616        try {
1617                Class clazz;
1618                if(classname!=null && classname.endsWith(".EHCacheLite")) clazz=EHCache.class;
1619                else clazz = ClassUtil.loadClass(config.getClassLoader(),classname);
1620                        if(!Reflector.isInstaneOf(clazz, Cache.class))
1621                                throw new ExpressionException("class ["+clazz.getName()+"] is not of type ["+Cache.class.getName()+"]");
1622                }
1623        catch (ClassException e) {
1624            throw new ExpressionException(e.getMessage());
1625                }
1626        
1627        Element parent=_getRootElement("cache");
1628
1629        if(name.equalsIgnoreCase(parent.getAttribute("default-template")))
1630                parent.removeAttribute("default-template");
1631        if(name.equalsIgnoreCase(parent.getAttribute("default-object")))
1632                parent.removeAttribute("default-object");
1633        if(name.equalsIgnoreCase(parent.getAttribute("default-query")))
1634                parent.removeAttribute("default-query");
1635        if(name.equalsIgnoreCase(parent.getAttribute("default-resource")))
1636                parent.removeAttribute("default-resource");
1637        if(name.equalsIgnoreCase(parent.getAttribute("default-function")))
1638                parent.removeAttribute("default-function");
1639        if(name.equalsIgnoreCase(parent.getAttribute("default-include")))
1640                parent.removeAttribute("default-include");
1641        
1642        
1643        if(_default==ConfigImpl.CACHE_DEFAULT_OBJECT){
1644                parent.setAttribute("default-object",name);
1645        }
1646        else if(_default==ConfigImpl.CACHE_DEFAULT_TEMPLATE){
1647                parent.setAttribute("default-template",name);
1648        }
1649        else if(_default==ConfigImpl.CACHE_DEFAULT_QUERY){
1650                parent.setAttribute("default-query",name);
1651        }
1652        else if(_default==ConfigImpl.CACHE_DEFAULT_RESOURCE){
1653                parent.setAttribute("default-resource",name);
1654        }
1655        else if(_default==ConfigImpl.CACHE_DEFAULT_FUNCTION){
1656                parent.setAttribute("default-function",name);
1657        }
1658        else if(_default==ConfigImpl.CACHE_DEFAULT_INCLUDE){
1659                parent.setAttribute("default-include",name);
1660        }
1661        
1662        // Update
1663        //boolean isUpdate=false;
1664        Element[] children = ConfigWebFactory.getChildren(parent,"connection");
1665        for(int i=0;i<children.length;i++) {
1666            String n=children[i].getAttribute("name");
1667            Element el=children[i];
1668            if(n.equalsIgnoreCase(name)) {
1669                el.setAttribute("class",classname);
1670                        //el.setAttribute("default",Caster.toString(_default));
1671                        el.setAttribute("custom",toStringURLStyle(custom));
1672                        el.setAttribute("read-only",Caster.toString(readOnly));
1673                        el.setAttribute("storage",Caster.toString(storage));
1674                        return;
1675                        }
1676          
1677        }
1678        
1679        // Insert
1680        Element el=doc.createElement("connection");
1681        parent.appendChild(el);
1682        el.setAttribute("name",name);
1683                el.setAttribute("class",classname);
1684                //el.setAttribute("default",Caster.toString(_default));
1685                el.setAttribute("custom",toStringURLStyle(custom));
1686                el.setAttribute("read-only",Caster.toString(readOnly));
1687                el.setAttribute("storage",Caster.toString(storage));
1688        
1689    }
1690        
1691        public void removeCacheDefaultConnection(int type) throws PageException {
1692        checkWriteAccess();
1693        
1694        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManagerImpl.TYPE_CACHE);
1695        if(!hasAccess)
1696            throw new SecurityException("no access to update cache connections");
1697        
1698        Element parent=_getRootElement("cache");
1699        if(type==ConfigImpl.CACHE_DEFAULT_OBJECT){
1700                parent.removeAttribute("default-object");
1701        }
1702        else if(type==ConfigImpl.CACHE_DEFAULT_TEMPLATE){
1703                parent.removeAttribute("default-template");
1704        }
1705        else if(type==ConfigImpl.CACHE_DEFAULT_QUERY){
1706                parent.removeAttribute("default-query");
1707        }
1708        else if(type==ConfigImpl.CACHE_DEFAULT_RESOURCE){
1709                parent.removeAttribute("default-resource");
1710        }
1711        else if(type==ConfigImpl.CACHE_DEFAULT_FUNCTION){
1712                parent.removeAttribute("default-function");
1713        }
1714        else if(type==ConfigImpl.CACHE_DEFAULT_INCLUDE){
1715                parent.removeAttribute("default-include");
1716        }
1717    }
1718        
1719        public void updateCacheDefaultConnection(int type,String name) throws PageException {
1720        checkWriteAccess();
1721        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManagerImpl.TYPE_CACHE);
1722        
1723        if(!hasAccess)
1724            throw new SecurityException("no access to update cache default connections");
1725        
1726        Element parent=_getRootElement("cache");
1727        if(type==ConfigImpl.CACHE_DEFAULT_OBJECT){
1728                parent.setAttribute("default-object", name);
1729        }
1730        else if(type==ConfigImpl.CACHE_DEFAULT_TEMPLATE){
1731                parent.setAttribute("default-template", name);
1732        }
1733        else if(type==ConfigImpl.CACHE_DEFAULT_QUERY){
1734                parent.setAttribute("default-query", name);
1735        }
1736        else if(type==ConfigImpl.CACHE_DEFAULT_RESOURCE){
1737                parent.setAttribute("default-resource", name);
1738        }
1739        else if(type==ConfigImpl.CACHE_DEFAULT_FUNCTION){
1740                parent.setAttribute("default-function", name);
1741        }
1742        else if(type==ConfigImpl.CACHE_DEFAULT_INCLUDE){
1743                parent.setAttribute("default-include", name);
1744        }
1745    }
1746        
1747    public void removeResourceProvider(Class clazz) throws PageException {
1748        checkWriteAccess();
1749        SecurityManager sm = config.getSecurityManager();
1750        short access = sm.getAccess(SecurityManager.TYPE_FILE);
1751        boolean hasAccess=access==SecurityManager.VALUE_YES;
1752        
1753        String className=clazz.getName();
1754        
1755        if(!hasAccess)
1756            throw new SecurityException("no access to remove resources");
1757        
1758        Element parent=_getRootElement("resources");
1759        
1760        // remove
1761        Element[] children = ConfigWebFactory.getChildren(parent,"resource-provider");
1762        for(int i=0;i<children.length;i++) {
1763            String cn=children[i].getAttribute("class");
1764            if(cn.equalsIgnoreCase(className)) {
1765                parent.removeChild(children[i]);                
1766                        break;
1767                        }
1768        }
1769        }       
1770    
1771    public void updateResourceProvider(String scheme, Class clazz,Struct arguments) throws PageException {
1772        updateResourceProvider(scheme, clazz, toStringCSSStyle(arguments));
1773    }
1774
1775        public void updateResourceProvider(String scheme, Class clazz,String arguments) throws PageException {
1776        checkWriteAccess();
1777        SecurityManager sm = config.getSecurityManager();
1778        short access = sm.getAccess(SecurityManager.TYPE_FILE);
1779        boolean hasAccess=access==SecurityManager.VALUE_YES;
1780        
1781        String className=clazz.getName();
1782        
1783        if(!hasAccess)
1784            throw new SecurityException("no access to update resources");
1785        
1786        // check parameters
1787        if(StringUtil.isEmpty(scheme))throw new ExpressionException("scheme can't be a empty value");
1788        
1789        Element parent=_getRootElement("resources");
1790        
1791        // Update
1792        Element[] children = ConfigWebFactory.getChildren(parent,"resource-provider");
1793        for(int i=0;i<children.length;i++) {
1794            String cn=children[i].getAttribute("class");
1795            if(cn.equalsIgnoreCase(className)) {
1796                        Element el=children[i];
1797                        el.setAttribute("scheme",scheme);
1798                        el.setAttribute("arguments",arguments);                
1799                        return ;
1800                        }
1801        }
1802        
1803        // Insert
1804        Element el=doc.createElement("resource-provider");
1805        parent.appendChild(el);
1806                el.setAttribute("scheme",scheme);
1807                el.setAttribute("arguments",arguments);  
1808                el.setAttribute("class",className);
1809        }       
1810        
1811        public void updateDefaultResourceProvider(Class clazz, String arguments) throws PageException {
1812        checkWriteAccess();
1813        SecurityManager sm = config.getSecurityManager();
1814        short access = sm.getAccess(SecurityManager.TYPE_FILE);
1815        boolean hasAccess=access==SecurityManager.VALUE_YES;
1816        
1817        String className=clazz.getName();
1818        
1819        if(!hasAccess)
1820            throw new SecurityException("no access to update resources");
1821        
1822        Element parent=_getRootElement("resources");
1823        
1824        // Update
1825        Element[] children = ConfigWebFactory.getChildren(parent,"default-resource-provider");
1826        for(int i=0;i<children.length;i++) {
1827            Element el=children[i];
1828                el.setAttribute("arguments",arguments);                
1829                return;
1830        }
1831        
1832        // Insert
1833        Element el=doc.createElement("default-resource-provider");
1834        parent.appendChild(el);
1835                el.setAttribute("arguments",arguments);  
1836                el.setAttribute("class",className);
1837        }
1838
1839    private int getDatasourceLength(ConfigImpl config) {
1840        Map ds = config.getDataSourcesAsMap();
1841        Iterator it = ds.keySet().iterator();
1842        int len=0;
1843        
1844        while(it.hasNext()) {
1845                if(!((DataSource)ds.get(it.next())).isReadOnly())len++;
1846        }
1847                return len;
1848        }
1849
1850
1851        private static String toStringURLStyle(Struct sct) {
1852        Iterator<Entry<Key, Object>> it = sct.entryIterator();
1853                Entry<Key, Object> e;
1854                StringBuilder rtn=new StringBuilder();
1855        while(it.hasNext()) {
1856            e = it.next();
1857            if(rtn.length()>0)rtn.append('&');
1858            rtn.append(URLEncoder.encode(e.getKey().getString()));
1859            rtn.append('=');
1860            rtn.append(URLEncoder.encode(Caster.toString(e.getValue(),"")));
1861        }
1862        return rtn.toString();
1863    }
1864
1865        private static String toStringCSSStyle(Struct sct) {
1866        //Collection.Key[] keys = sct.keys();
1867                StringBuilder rtn=new StringBuilder();
1868        Iterator<Entry<Key, Object>> it = sct.entryIterator();
1869                Entry<Key, Object> e;
1870        
1871                while(it.hasNext()) {
1872                        e = it.next();
1873            if(rtn.length()>0)rtn.append(';');
1874            rtn.append(encode(e.getKey().getString()));
1875            rtn.append(':');
1876            rtn.append(encode(Caster.toString(e.getValue(),"")));
1877        }
1878        return rtn.toString();
1879    }
1880
1881    private static String encode(String str) {
1882                try {
1883                        return URLEncodedFormat.invoke(str, "UTF-8",false);
1884                } catch (PageException e) {
1885                        return URLEncoder.encode(str);
1886                }
1887        }
1888
1889
1890        public Query getResourceProviders() throws PageException {
1891        checkReadAccess();
1892        // check parameters
1893        Element parent=_getRootElement("resources");
1894        Element[] elProviders = ConfigWebFactory.getChildren(parent,"resource-provider");
1895        Element[] elDefaultProviders = ConfigWebFactory.getChildren(parent,"default-resource-provider");
1896        ResourceProvider[] providers = config.getResourceProviders();
1897        ResourceProvider defaultProvider = config.getDefaultResourceProvider();
1898                
1899        Query qry=new QueryImpl(new String[]{"support","scheme","caseSensitive","default","class","arguments"},elProviders.length+elDefaultProviders.length,"resourceproviders");
1900        int row=1;
1901        for(int i=0;i<elDefaultProviders.length;i++) {
1902                getResourceProviders(new ResourceProvider[]{defaultProvider},qry,elDefaultProviders[i],row++,Boolean.TRUE);
1903            }
1904        for(int i=0;i<elProviders.length;i++) {
1905                getResourceProviders(providers,qry,elProviders[i],row++,Boolean.FALSE);
1906            }
1907        return qry;
1908    }
1909    
1910    private void getResourceProviders(ResourceProvider[] providers,Query qry,Element p, int row,Boolean def) throws PageException {
1911        Array support=new ArrayImpl();
1912            String clazz=p.getAttribute("class");
1913                qry.setAt("scheme",row,p.getAttribute("scheme"));
1914                qry.setAt("arguments",row,p.getAttribute("arguments"));
1915                qry.setAt("class",row,clazz);
1916                for(int i=0;i<providers.length;i++) {
1917                        if(providers[i].getClass().getName().equals(clazz)){
1918                                if(providers[i].isAttributesSupported())support.append("attributes");
1919                    if(providers[i].isModeSupported())support.append("mode");
1920                    qry.setAt("support",row,ListUtil.arrayToList(support, ","));
1921                    qry.setAt("scheme",row,providers[i].getScheme());
1922                    qry.setAt("caseSensitive",row,Caster.toBoolean(providers[i].isCaseSensitive()));
1923                    qry.setAt("default",row,def);
1924                                break;
1925                        }
1926                }
1927        }
1928
1929
1930        /**
1931     * remove a DataSource Connection
1932     * @param name
1933     * @throws ExpressionException
1934     * @throws SecurityException 
1935     */
1936    public void removeDataSource(String name) throws ExpressionException, SecurityException {
1937        checkWriteAccess();
1938        // check parameters
1939        if(name==null || name.length()==0)
1940            throw new ExpressionException("name for Datasource Connection can be a empty value");
1941        
1942
1943        Element datasources=_getRootElement("data-sources");
1944
1945        Element[] children = ConfigWebFactory.getChildren(datasources,"data-source");
1946        for(int i=0;i<children.length;i++) {
1947            String n=children[i].getAttribute("name"); 
1948                if(n!=null && n.equalsIgnoreCase(name)) {
1949                  datasources.removeChild(children[i]);
1950                        }
1951            }
1952    }
1953
1954        public void removeCacheConnection(String name) throws ExpressionException, SecurityException {
1955                checkWriteAccess();
1956                
1957                boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManagerImpl.TYPE_CACHE);
1958                if(!hasAccess)
1959            throw new SecurityException("no access to remove cache connection");
1960        
1961                
1962        // check parameters
1963        if(StringUtil.isEmpty(name))
1964            throw new ExpressionException("name for Cache Connection can be a empty value");
1965        
1966        Element parent=_getRootElement("cache");
1967        
1968        // remove default flag
1969        if(name.equalsIgnoreCase(parent.getAttribute("default-object")))
1970                parent.removeAttribute("default-object");
1971        if(name.equalsIgnoreCase(parent.getAttribute("default-template")))
1972                parent.removeAttribute("default-template");
1973        if(name.equalsIgnoreCase(parent.getAttribute("default-query")))
1974                parent.removeAttribute("default-query");
1975        if(name.equalsIgnoreCase(parent.getAttribute("default-resource")))
1976                parent.removeAttribute("default-resource");
1977        
1978        // remove element
1979        Element[] children = ConfigWebFactory.getChildren(parent,"connection");
1980        for(int i=0;i<children.length;i++) {
1981            String n=children[i].getAttribute("name"); 
1982                if(n!=null && n.equalsIgnoreCase(name)) {
1983                        Map<String, CacheConnection> conns = config.getCacheConnections();
1984                        CacheConnection cc= conns.get(n.toLowerCase());
1985                        if(cc!=null)Util.removeEL(config instanceof ConfigWeb?(ConfigWeb)config:null,cc);
1986                  parent.removeChild(children[i]);
1987                        }
1988            }
1989        
1990        }
1991        
1992
1993        public void removeCacheGatewayEntry(String name) throws PageException {
1994                checkWriteAccess();
1995        
1996                boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManagerImpl.TYPE_GATEWAY);
1997        if(!hasAccess)
1998            throw new SecurityException("no access to remove gateway entry");
1999        
2000        if(StringUtil.isEmpty(name))
2001            throw new ExpressionException("name for Gateway Id can be a empty value");
2002        
2003        Element parent=_getRootElement("gateways");
2004        
2005        // remove element
2006        Element[] children = ConfigWebFactory.getChildren(parent,"gateway");
2007        for(int i=0;i<children.length;i++) {
2008            String n=children[i].getAttribute("id"); 
2009                if(n!=null && n.equalsIgnoreCase(name)) {
2010                        Map conns = ((ConfigWebImpl)config).getGatewayEngine().getEntries();
2011                        GatewayEntry ge=(GatewayEntry) conns.get(n);
2012                        if(ge!=null){
2013                                ((ConfigWebImpl)config).getGatewayEngine().remove(ge);
2014                        }
2015                        parent.removeChild(children[i]);
2016                        }
2017            }
2018        }
2019
2020        
2021        
2022    public void removeRemoteClient(String url) throws ExpressionException, SecurityException {
2023        checkWriteAccess();
2024        
2025        // SNSN
2026        
2027        
2028        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManagerImpl.TYPE_REMOTE);
2029        if(!hasAccess)
2030            throw new SecurityException("no access to remove remote client settings");
2031        
2032        
2033        
2034        // check parameters
2035        if(StringUtil.isEmpty(url))
2036            throw new ExpressionException("url for Remote Client can be a empty value");
2037        
2038
2039        Element clients=_getRootElement("remote-clients");
2040
2041        Element[] children = ConfigWebFactory.getChildren(clients,"remote-client");
2042        for(int i=0;i<children.length;i++) {
2043            String n=children[i].getAttribute("url"); 
2044                if(n!=null && n.equalsIgnoreCase(url)) {
2045                  clients.removeChild(children[i]);
2046                        }
2047            }
2048    }
2049    
2050    /**
2051     *  update PSQ State
2052     * @param psq Preserver Single Quote
2053     * @throws SecurityException
2054     */
2055    public void updatePSQ(Boolean psq) throws SecurityException {
2056        checkWriteAccess();
2057        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_DATASOURCE);
2058        
2059        if(!hasAccess) throw new SecurityException("no access to update datsource connections");
2060        
2061        Element datasources=_getRootElement("data-sources");
2062        datasources.setAttribute("psq",Caster.toString(psq,""));
2063        if(datasources.hasAttribute("preserve-single-quote"))
2064                datasources.removeAttribute("preserve-single-quote");
2065    }
2066
2067
2068        public void updateInspectTemplate(String str) throws SecurityException {
2069                checkWriteAccess();
2070        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2071        
2072        if(!hasAccess) throw new SecurityException("no access to update");
2073        
2074        Element datasources=_getRootElement("java");
2075        datasources.setAttribute("inspect-template",str);
2076
2077        }
2078        
2079
2080        public void updateTypeChecking(Boolean typeChecking) throws SecurityException {
2081                checkWriteAccess();
2082        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2083        
2084        if(!hasAccess) throw new SecurityException("no access to update");
2085        
2086        Element datasources=_getRootElement("application");
2087        if(typeChecking==null)datasources.removeAttribute("type-checking");
2088        else datasources.setAttribute("type-checking",Caster.toString(typeChecking.booleanValue()));
2089
2090        }
2091        
2092        
2093    
2094    
2095    /**
2096     * sets the scope cascading type
2097     * @param type (ServletConfigImpl.SCOPE_XYZ)
2098     * @throws SecurityException
2099     */ 
2100    public void updateScopeCascadingType(String type) throws SecurityException {
2101        checkWriteAccess();
2102        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2103        
2104        if(!hasAccess) throw new SecurityException("no access to update scope setting");
2105        
2106        
2107        Element scope=_getRootElement("scope");
2108        if(type.equalsIgnoreCase("strict"))        scope.setAttribute("cascading","strict");
2109        else if(type.equalsIgnoreCase("small"))    scope.setAttribute("cascading","small");
2110        else if(type.equalsIgnoreCase("standard")) scope.setAttribute("cascading","standard");
2111        else                                       scope.setAttribute("cascading","standard");
2112        
2113    }
2114    
2115    /**
2116     * sets the scope cascading type
2117     * @param type (ServletConfigImpl.SCOPE_XYZ)
2118     * @throws SecurityException
2119     */ 
2120    public void updateScopeCascadingType(short type) throws SecurityException {
2121        checkWriteAccess();
2122        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2123        if(!hasAccess)
2124            throw new SecurityException("no access to update scope setting");
2125        
2126        //lucee.print.ln("********........type:"+type);
2127        Element scope=_getRootElement("scope");
2128        if(type==ConfigWeb.SCOPE_STRICT) scope.setAttribute("cascading","strict");
2129        else if(type==ConfigWeb.SCOPE_SMALL) scope.setAttribute("cascading","small");
2130        else if(type==ConfigWeb.SCOPE_STANDARD) scope.setAttribute("cascading","standard");
2131        
2132    }
2133    
2134    /**
2135     * sets if allowed implicid query call
2136     * @param allow
2137     * @throws SecurityException
2138     */
2139    public void updateAllowImplicidQueryCall(Boolean allow) throws SecurityException {
2140        checkWriteAccess();
2141        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2142        
2143        if(!hasAccess) throw new SecurityException("no access to update scope setting");
2144        
2145        Element scope=_getRootElement("scope");
2146        scope.setAttribute("cascade-to-resultset",Caster.toString(allow,""));
2147        
2148    }
2149    
2150    public void updateMergeFormAndUrl(Boolean merge) throws SecurityException {
2151        checkWriteAccess();
2152        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2153        
2154        if(!hasAccess) throw new SecurityException("no access to update scope setting");
2155        
2156        Element scope=_getRootElement("scope");
2157        scope.setAttribute("merge-url-form",Caster.toString(merge,""));
2158        
2159    }
2160    
2161    /**
2162     * updates request timeout value
2163     * @param span
2164     * @throws SecurityException
2165     * @throws ApplicationException 
2166     */
2167    public void updateRequestTimeout(TimeSpan span) throws SecurityException, ApplicationException {
2168        checkWriteAccess();
2169        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2170        
2171        if(!hasAccess) throw new SecurityException("no access to update scope setting");
2172        
2173        Element scope=_getRootElement("scope");
2174        
2175        Element application=_getRootElement("application");
2176        if(span!=null){
2177                if(span.getMillis()<=0)
2178                        throw new ApplicationException("value must be a positive number");
2179                application.setAttribute("requesttimeout",span.getDay()+","+span.getHour()+","+span.getMinute()+","+span.getSecond());
2180        }
2181        else application.removeAttribute("requesttimeout");
2182        
2183        // remove deprecated attribute
2184        if(scope.hasAttribute("requesttimeout"))
2185                scope.removeAttribute("requesttimeout");
2186    }
2187    
2188    /**
2189     * updates session timeout value
2190     * @param span
2191     * @throws SecurityException
2192     */
2193    public void updateSessionTimeout(TimeSpan span) throws SecurityException {
2194        checkWriteAccess();
2195        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2196        
2197        if(!hasAccess) throw new SecurityException("no access to update scope setting");
2198        
2199        Element scope=_getRootElement("scope");
2200        if(span!=null)scope.setAttribute("sessiontimeout",span.getDay()+","+span.getHour()+","+span.getMinute()+","+span.getSecond());
2201        else scope.removeAttribute("sessiontimeout");
2202    }
2203    
2204    
2205
2206
2207        public void updateClientStorage(String storage) throws SecurityException, ApplicationException {
2208                updateStorage("client", storage);
2209        }
2210
2211
2212        public void updateSessionStorage(String storage) throws SecurityException, ApplicationException {
2213                updateStorage("session", storage);
2214        }
2215        
2216
2217        private void updateStorage(String storageName,String storage) throws SecurityException, ApplicationException {
2218                checkWriteAccess();
2219        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2220        
2221        if(!hasAccess) throw new SecurityException("no access to update scope setting");
2222        storage=validateStorage(storage);
2223        
2224        
2225        Element scope=_getRootElement("scope");
2226        if(!StringUtil.isEmpty(storage,true))scope.setAttribute(storageName+"storage",storage);
2227        else scope.removeAttribute(storageName+"storage");
2228        }
2229    
2230    
2231    
2232    private String validateStorage(String storage) throws ApplicationException {
2233        storage=storage.trim().toLowerCase();
2234        
2235        // empty
2236        if(StringUtil.isEmpty(storage,true)) return "";
2237        
2238        // standard storages
2239        if("cookie".equals(storage) || "memory".equals(storage) || "file".equals(storage)) 
2240                return storage;
2241        
2242        // aliases
2243        if("ram".equals(storage)) return "memory";
2244        if("registry".equals(storage)) return "file";
2245        
2246        // datasource
2247        DataSource  ds = config.getDataSource(storage,null);
2248        if(ds!=null) {
2249                if(ds.isStorage())return storage;
2250                throw new ApplicationException("datasource ["+storage+"] is not enabled to be used as session/client storage");
2251        }
2252                
2253        // cache
2254        CacheConnection cc = Util.getCacheConnection(config, storage,null);
2255        if(cc!=null) {
2256                if(cc.isStorage())return storage;
2257                throw new ApplicationException("cache ["+storage+"] is not enabled to be used as session/client storage");
2258        }
2259        
2260        String sdx=StringUtil.soundex(storage);
2261        
2262        // check if a datasource has a similar name 
2263        DataSource[] sources = config.getDataSources();
2264        for(int i=0;i<sources.length;i++){
2265                if(StringUtil.soundex(sources[i].getName()).equals(sdx))
2266                        throw new ApplicationException("no matching storage for ["+storage+"] found, did you mean ["+sources[i].getName()+"]");
2267        }
2268        
2269        // check if a cache has a similar name 
2270        Iterator<String> it = config.getCacheConnections().keySet().iterator();
2271        String name;
2272        while(it.hasNext()){
2273                name=it.next();
2274                if(StringUtil.soundex(name).equals(sdx))
2275                        throw new ApplicationException( "no matching storage for ["+storage+"] found, did you mean ["+name+"]");
2276        }
2277        
2278                
2279        throw new ApplicationException("no matching storage for ["+storage+"] found");
2280        }
2281
2282
2283        /**
2284     * updates session timeout value
2285     * @param span
2286     * @throws SecurityException
2287     */
2288    public void updateClientTimeout(TimeSpan span) throws SecurityException {
2289        checkWriteAccess();
2290        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2291        
2292        if(!hasAccess) throw new SecurityException("no access to update scope setting");
2293        
2294        Element scope=_getRootElement("scope");
2295        if(span!=null)scope.setAttribute("clienttimeout",span.getDay()+","+span.getHour()+","+span.getMinute()+","+span.getSecond());
2296        else scope.removeAttribute("clienttimeout");
2297        
2298        // deprecated
2299        if(scope.hasAttribute("client-max-age"))scope.removeAttribute("client-max-age");
2300       
2301        
2302    }
2303    
2304
2305    public void updateCFMLWriterType(String writerType) throws SecurityException, ApplicationException {
2306        checkWriteAccess();
2307        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2308        if(!hasAccess) throw new SecurityException("no access to update scope setting");
2309        
2310        Element scope=_getRootElement("setting");
2311        writerType=writerType.trim();
2312        
2313        // remove
2314        if(StringUtil.isEmpty(writerType)) {
2315                if(scope.hasAttribute("cfml-writer"))scope.removeAttribute("cfml-writer");
2316                return;
2317        }
2318        
2319        // update
2320        if(!"white-space".equalsIgnoreCase(writerType) && 
2321                        !"white-space-pref".equalsIgnoreCase(writerType) && 
2322                        !"regular".equalsIgnoreCase(writerType))
2323                throw new ApplicationException("invalid writer type defintion ["+writerType+"], valid types are [white-space, white-space-pref, regular]");
2324        
2325        scope.setAttribute("cfml-writer",writerType.toLowerCase());
2326    } 
2327
2328    /*public void updateSuppressWhitespace(Boolean value) throws SecurityException {
2329        checkWriteAccess();
2330        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2331        
2332        if(!hasAccess) throw new SecurityException("no access to update scope setting");
2333        
2334        Element scope=_getRootElement("setting");
2335        scope.setAttribute("suppress-whitespace",Caster.toString(value,""));
2336    }*/
2337    
2338    public void updateSuppressContent(Boolean value) throws SecurityException {
2339        checkWriteAccess();
2340        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2341        
2342        if(!hasAccess) throw new SecurityException("no access to update scope setting");
2343        
2344        Element scope=_getRootElement("setting");
2345        scope.setAttribute("suppress-content",Caster.toString(value,""));
2346    }
2347    
2348    public void updateShowVersion(Boolean value) throws SecurityException {
2349        checkWriteAccess();
2350        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2351        
2352        if(!hasAccess) throw new SecurityException("no access to update scope setting");
2353        
2354        Element scope=_getRootElement("setting");
2355        scope.setAttribute("show-version",Caster.toString(value,""));
2356    }
2357    
2358    public void updateAllowCompression(Boolean value) throws SecurityException {
2359        checkWriteAccess();
2360        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2361        
2362        if(!hasAccess) throw new SecurityException("no access to update scope setting");
2363        
2364        Element scope=_getRootElement("setting");
2365        scope.setAttribute("allow-compression",Caster.toString(value,""));
2366    }
2367    
2368    public void updateContentLength(Boolean value) throws SecurityException {
2369        checkWriteAccess();
2370        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2371        
2372        if(!hasAccess) throw new SecurityException("no access to update scope setting");
2373        
2374        Element scope=_getRootElement("setting");
2375        scope.setAttribute("content-length",Caster.toString(value,""));
2376    }
2377    
2378
2379        public void updateBufferOutput(Boolean value) throws SecurityException {
2380                checkWriteAccess();
2381        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2382        
2383        if(!hasAccess) throw new SecurityException("no access to update scope setting");
2384        
2385        Element scope=_getRootElement("setting");
2386        scope.setAttribute("buffer-output",Caster.toString(value,""));
2387        }
2388    
2389    /**
2390     * updates request timeout value
2391     * @param span
2392     * @throws SecurityException
2393     */
2394    public void updateApplicationTimeout(TimeSpan span) throws SecurityException {
2395        checkWriteAccess();
2396        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2397        
2398        if(!hasAccess) throw new SecurityException("no access to update scope setting");
2399        
2400        Element scope=_getRootElement("scope");
2401        if(span!=null)scope.setAttribute("applicationtimeout",span.getDay()+","+span.getHour()+","+span.getMinute()+","+span.getSecond());
2402        else scope.removeAttribute("applicationtimeout");
2403    }
2404
2405    public void updateApplicationListener(String type,String mode) throws SecurityException {
2406        checkWriteAccess();
2407        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2408        
2409        if(!hasAccess) throw new SecurityException("no access to update listener type");
2410        
2411        Element scope=_getRootElement("application");
2412        scope.setAttribute("listener-type",type.toLowerCase().trim());
2413        scope.setAttribute("listener-mode",mode.toLowerCase().trim());
2414    }
2415    
2416    public void updateProxy(boolean enabled,String server, int port, String username, String password) throws SecurityException {
2417        checkWriteAccess();
2418        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2419        
2420        if(!hasAccess) throw new SecurityException("no access to update listener type");
2421        
2422        Element proxy=_getRootElement("proxy");
2423        proxy.setAttribute("enabled",Caster.toString(enabled));
2424        if(!StringUtil.isEmpty(server))         proxy.setAttribute("server",server);
2425        if(port>0)                                                   proxy.setAttribute("port",Caster.toString(port));
2426        if(!StringUtil.isEmpty(username))       proxy.setAttribute("username",username);
2427        if(!StringUtil.isEmpty(password))       proxy.setAttribute("password",password);
2428    }
2429    
2430    /*public void removeProxy() throws SecurityException {
2431        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2432        if(!hasAccess) throw new SecurityException("no access to remove proxy settings");
2433        
2434        Element proxy=_getRootElement("proxy");
2435        proxy.removeAttribute("server");
2436        proxy.removeAttribute("port");
2437        proxy.removeAttribute("username");
2438        proxy.removeAttribute("password");
2439    }*/
2440    
2441    /**
2442     * enable or desable session management
2443     * @param sessionManagement
2444     * @throws SecurityException
2445     */
2446    public void updateSessionManagement(Boolean sessionManagement) throws SecurityException {
2447        checkWriteAccess();
2448        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2449        
2450        if(!hasAccess)
2451            throw new SecurityException("no access to update scope setting");
2452        
2453        Element scope=_getRootElement("scope");
2454        scope.setAttribute("sessionmanagement",Caster.toString(sessionManagement,""));
2455    }
2456    
2457    /**
2458     * enable or desable client management
2459     * @param clientManagement
2460     * @throws SecurityException
2461     */
2462    public void updateClientManagement(Boolean clientManagement) throws SecurityException {
2463        checkWriteAccess();
2464        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2465        
2466        if(!hasAccess)
2467            throw new SecurityException("no access to update scope setting");
2468        
2469        Element scope=_getRootElement("scope");
2470        scope.setAttribute("clientmanagement",Caster.toString(clientManagement,""));
2471    }
2472    
2473    /**
2474     * set if client cookies are enabled or not
2475     * @param clientCookies
2476     * @throws SecurityException
2477     */
2478    public void updateClientCookies(Boolean clientCookies) throws SecurityException {
2479        checkWriteAccess();
2480        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2481        if(!hasAccess)
2482            throw new SecurityException("no access to update scope setting");
2483        
2484        Element scope=_getRootElement("scope");
2485        scope.setAttribute("setclientcookies",Caster.toString(clientCookies,""));
2486    }
2487    
2488    public void updateCGIReadonly(Boolean cgiReadonly) throws SecurityException {
2489        checkWriteAccess();
2490        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2491        if(!hasAccess)
2492            throw new SecurityException("no access to update scope setting");
2493        
2494        Element scope=_getRootElement("scope");
2495        scope.setAttribute("cgi-readonly",Caster.toString(cgiReadonly,""));
2496    }
2497    
2498    /**
2499     * set if domain cookies are enabled or not
2500     * @param domainCookies
2501     * @throws SecurityException
2502     */
2503    public void updateDomaincookies(Boolean domainCookies) throws SecurityException {
2504        checkWriteAccess();
2505        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2506        if(!hasAccess)
2507            throw new SecurityException("no access to update scope setting");
2508        
2509        Element scope=_getRootElement("scope");
2510        scope.setAttribute("setdomaincookies",Caster.toString(domainCookies,""));
2511    }
2512    
2513    /**
2514     * update the locale
2515     * @param locale
2516     * @throws SecurityException
2517     */
2518    public void updateLocale(String locale) throws SecurityException {
2519        checkWriteAccess();
2520        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2521        if(!hasAccess)
2522            throw new SecurityException("no access to update regional setting");
2523        
2524        Element scope=_getRootElement("regional");
2525        scope.setAttribute("locale",locale.trim());
2526    }
2527
2528    public void updateMonitorEnabled(boolean updateMonitorEnabled) throws SecurityException {
2529        checkWriteAccess();
2530        
2531        Element scope=_getRootElement("monitoring");
2532        scope.setAttribute("enabled",Caster.toString(updateMonitorEnabled));
2533    }
2534    
2535    
2536    
2537    public void updateScriptProtect(String strScriptProtect) throws SecurityException {
2538        checkWriteAccess();
2539        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2540        if(!hasAccess)
2541            throw new SecurityException("no access to update script protect");
2542        
2543        Element scope=_getRootElement("application");
2544        scope.setAttribute("script-protect",strScriptProtect.trim());
2545    }
2546    
2547    public void updateAllowURLRequestTimeout(Boolean allowURLRequestTimeout) throws SecurityException {
2548        checkWriteAccess();
2549        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2550        if(!hasAccess)
2551            throw new SecurityException("no access to update AllowURLRequestTimeout");
2552        
2553        Element scope=_getRootElement("application");
2554        scope.setAttribute("allow-url-requesttimeout",Caster.toString(allowURLRequestTimeout,""));
2555    }
2556
2557        public void updateQueue(Integer max, Integer timeout, Boolean enable) throws SecurityException {
2558                checkWriteAccess();
2559        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2560        if(!hasAccess) throw new SecurityException("no access to update queue settings");
2561        
2562        Element queue=_getRootElement("queue");
2563     // max
2564        if(max==null) queue.removeAttribute("max");
2565        else queue.setAttribute("max",Caster.toString(max,""));
2566     // total
2567        if(timeout==null) queue.removeAttribute("timeout");
2568        else queue.setAttribute("timeout",Caster.toString(timeout,""));
2569     // enable
2570        if(enable==null) queue.removeAttribute("enable");
2571        else queue.setAttribute("enable",Caster.toString(enable,""));
2572        }
2573    
2574    public void updateScriptProtect(int scriptProtect) throws SecurityException { 
2575        updateScriptProtect(AppListenerUtil.translateScriptProtect(scriptProtect));
2576    }
2577    
2578    /**
2579     * update the timeZone
2580     * @param timeZone
2581     * @throws SecurityException
2582     */
2583    public void updateTimeZone(String timeZone) throws SecurityException {
2584        checkWriteAccess();
2585        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2586        if(!hasAccess)
2587            throw new SecurityException("no access to update regional setting");
2588        
2589        Element regional=_getRootElement("regional");
2590        regional.setAttribute("timezone",timeZone.trim());
2591        
2592    }
2593
2594    /**
2595     * update the timeServer
2596     * @param timeServer
2597     * @param useTimeServer 
2598     * @throws PageException 
2599     */
2600    public void updateTimeServer(String timeServer, Boolean useTimeServer) throws PageException {
2601        checkWriteAccess();
2602       if(useTimeServer!=null && useTimeServer.booleanValue() && !StringUtil.isEmpty(timeServer,true)) {
2603            try {
2604                new NtpClient(timeServer).getOffset();
2605            } catch (IOException e) {
2606                throw new ExpressionException("invalid timeserver (NTP) ["+timeServer+"] ");
2607            }
2608       }
2609        
2610       boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2611       if(!hasAccess)
2612            throw new SecurityException("no access to update regional setting");
2613        
2614        Element scope=_getRootElement("regional");
2615        scope.setAttribute("timeserver",timeServer.trim());
2616        if(useTimeServer!=null)scope.setAttribute("use-timeserver",Caster.toString(useTimeServer));
2617        else scope.removeAttribute("use-timeserver");
2618    }
2619    
2620    /**
2621     * update the baseComponent
2622     * @param baseComponent
2623     * @throws SecurityException
2624     */
2625    public void updateBaseComponent(String baseComponent) throws SecurityException {
2626        checkWriteAccess();
2627        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2628        if(!hasAccess)
2629            throw new SecurityException("no access to update component setting");
2630        //config.resetBaseComponentPage();
2631        Element scope=_getRootElement("component");
2632        //if(baseComponent.trim().length()>0)
2633                scope.setAttribute("base",baseComponent);
2634    }
2635    
2636    
2637
2638        public void updateComponentDeepSearch(Boolean deepSearch) throws SecurityException {
2639                checkWriteAccess();
2640            boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2641            if(!hasAccess)
2642                throw new SecurityException("no access to update component setting");
2643            //config.resetBaseComponentPage();
2644            Element scope=_getRootElement("component");
2645            //if(baseComponent.trim().length()>0)
2646            if(deepSearch!=null)
2647        scope.setAttribute("deep-search",Caster.toString(deepSearch.booleanValue()));
2648            
2649            else {
2650                if(scope.hasAttribute("deep-search"))
2651                        scope.removeAttribute("deep-search");
2652            }
2653                
2654        }
2655    
2656
2657    public void updateComponentDefaultImport(String componentDefaultImport) throws SecurityException {
2658        checkWriteAccess();
2659        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2660        if(!hasAccess)
2661            throw new SecurityException("no access to update component setting");
2662        //config.resetBaseComponentPage();
2663        Element scope=_getRootElement("component");
2664        //if(baseComponent.trim().length()>0)
2665                scope.setAttribute("component-default-import",componentDefaultImport);
2666    }
2667    
2668    
2669    
2670    
2671    /**
2672     * update the Component Data Member default access type
2673     * @param access
2674     * @throws SecurityException
2675     * @throws ExpressionException 
2676     */
2677    public void updateComponentDataMemberDefaultAccess(String strAccess) throws SecurityException, ExpressionException {
2678        checkWriteAccess(); 
2679        
2680        
2681        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2682        if(!hasAccess)
2683            throw new SecurityException("no access to update component setting");
2684        
2685        Element scope=_getRootElement("component");
2686
2687        if(StringUtil.isEmpty(strAccess)){
2688                scope.setAttribute("data-member-default-access","");
2689        }
2690        else{
2691                scope.setAttribute("data-member-default-access",ComponentUtil.toStringAccess(ComponentUtil.toIntAccess(strAccess)));
2692        }
2693    } 
2694    
2695    /**
2696     * update the Component Data Member default access type
2697     * @param accessType
2698     * @throws SecurityException
2699     */
2700    public void updateTriggerDataMember(Boolean triggerDataMember) throws SecurityException {
2701        checkWriteAccess();
2702        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2703        if(!hasAccess)
2704            throw new SecurityException("no access to update trigger-data-member");
2705        
2706        Element scope=_getRootElement("component");
2707        scope.setAttribute("trigger-data-member",Caster.toString(triggerDataMember,""));
2708    }
2709
2710        public void updateComponentUseShadow(Boolean useShadow) throws SecurityException {
2711        checkWriteAccess();
2712                boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2713                if(!hasAccess)
2714            throw new SecurityException("no access to update use-shadow");
2715        
2716        Element scope=_getRootElement("component");
2717        scope.setAttribute("use-shadow",Caster.toString(useShadow,""));
2718        }
2719
2720        public void updateComponentLocalSearch(Boolean componentLocalSearch) throws SecurityException {
2721        checkWriteAccess();
2722                boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2723                if(!hasAccess)
2724            throw new SecurityException("no access to update component Local Search");
2725        
2726        Element scope=_getRootElement("component");
2727        scope.setAttribute("local-search",Caster.toString(componentLocalSearch,""));
2728        }
2729        
2730        public void updateComponentPathCache(Boolean componentPathCache) throws SecurityException {
2731                checkWriteAccess();
2732                boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2733                if(!hasAccess)
2734            throw new SecurityException("no access to update component Cache Path");
2735        
2736        Element scope=_getRootElement("component");
2737        if(!Caster.toBooleanValue(componentPathCache,false))
2738                config.clearComponentCache();
2739        scope.setAttribute("use-cache-path",Caster.toString(componentPathCache,""));
2740        }
2741        public void updateCTPathCache(Boolean ctPathCache) throws SecurityException {
2742                checkWriteAccess();
2743                if(!ConfigWebUtil.hasAccess(config, SecurityManager.TYPE_CUSTOM_TAG)) 
2744                        throw new SecurityException("no access to update custom tag setting");
2745                
2746                 if(!Caster.toBooleanValue(ctPathCache,false))
2747                        config.clearCTCache();
2748                Element scope=_getRootElement("custom-tag");
2749        scope.setAttribute("use-cache-path",Caster.toString(ctPathCache,""));
2750        }
2751
2752        
2753        
2754        
2755    /**
2756     * updates if debugging or not
2757     * @param debug if value is null server setting is used
2758     * @throws SecurityException
2759     */
2760    public void updateDebug(Boolean debug, Boolean database, Boolean exception, Boolean tracing, Boolean dump, Boolean timer, 
2761                Boolean implicitAccess, Boolean queryUsage) throws SecurityException {
2762        checkWriteAccess();
2763        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_DEBUGGING);
2764        if(!hasAccess)
2765            throw new SecurityException("no access to change debugging settings");
2766        Element debugging=_getRootElement("debugging");
2767        
2768        if(debug!=null)debugging.setAttribute("debug",Caster.toString(debug.booleanValue()));
2769        else debugging.removeAttribute("debug");
2770        
2771        if(database!=null)debugging.setAttribute("database",Caster.toString(database.booleanValue()));
2772        else debugging.removeAttribute("database");
2773        
2774        if(exception!=null)debugging.setAttribute("exception",Caster.toString(exception.booleanValue()));
2775        else debugging.removeAttribute("exception");
2776        
2777        if(tracing!=null)debugging.setAttribute("tracing",Caster.toString(tracing.booleanValue()));
2778        else debugging.removeAttribute("tracing");
2779        
2780        if(dump!=null)debugging.setAttribute("dump",Caster.toString(dump.booleanValue()));
2781        else debugging.removeAttribute("dump");
2782        
2783        if(timer!=null)debugging.setAttribute("timer",Caster.toString(timer.booleanValue()));
2784        else debugging.removeAttribute("timer");
2785
2786        if(implicitAccess!=null)debugging.setAttribute("implicit-access",Caster.toString(implicitAccess.booleanValue()));
2787        else debugging.removeAttribute("implicit-access");
2788        
2789        if(queryUsage!=null)debugging.setAttribute("query-usage",Caster.toString(queryUsage.booleanValue()));
2790        else debugging.removeAttribute("query-usage");
2791        
2792        
2793    }
2794
2795    /**
2796     * updates the DebugTemplate
2797     * @param template
2798     * @throws SecurityException
2799     */
2800    public void updateDebugTemplate(String template) throws SecurityException {
2801        checkWriteAccess();
2802        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_DEBUGGING);
2803        if(!hasAccess)
2804            throw new SecurityException("no access to change debugging settings");
2805
2806        Element debugging=_getRootElement("debugging");
2807        //if(template.trim().length()>0)
2808                debugging.setAttribute("template",template);
2809    }
2810    
2811    /**
2812     * updates the ErrorTemplate
2813     * @param template
2814     * @throws SecurityException
2815     */
2816    public void updateErrorTemplate(int statusCode,String template) throws SecurityException {
2817        checkWriteAccess();
2818        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_DEBUGGING);
2819        if(!hasAccess)
2820            throw new SecurityException("no access to change error settings");
2821
2822        Element error=_getRootElement("error");
2823        //if(template.trim().length()>0)
2824                error.setAttribute("template-"+statusCode,template);
2825    }
2826    
2827
2828    public void updateErrorStatusCode(Boolean doStatusCode) throws SecurityException {
2829        checkWriteAccess();
2830        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_DEBUGGING);
2831        if(!hasAccess)
2832            throw new SecurityException("no access to change error settings");
2833
2834        Element error=_getRootElement("error");
2835        error.setAttribute("status-code",Caster.toString(doStatusCode,""));
2836    }
2837
2838    /**
2839     * updates the DebugTemplate
2840     * @param template
2841     * @throws SecurityException
2842     */
2843    public void updateComponentDumpTemplate(String template) throws SecurityException {
2844        checkWriteAccess();
2845        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
2846        if(!hasAccess)
2847            throw new SecurityException("no access to update component setting");
2848        
2849        Element component=_getRootElement("component");
2850        //if(template.trim().length()>0)
2851                component.setAttribute("dump-template",template);
2852    }
2853    
2854    /* *
2855     * updates the if memory usage will be logged or not
2856     * @param logMemoryUsage
2857     * @throws SecurityException
2858     * /
2859    public void updateLogMemoryUsage(boolean logMemoryUsage) throws SecurityException {
2860        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_DEBUGGING);
2861        if(!hasAccess)
2862            throw new SecurityException("no access to change debugging settings");
2863        
2864        Element debugging=_getRootElement("debugging");
2865        debugging.setAttribute("log-memory-usage",Caster.toString(logMemoryUsage));
2866    }*/
2867    
2868    /* *
2869     * updates the Memory Logger
2870     * @param memoryLogger
2871     * @throws SecurityException
2872     * /
2873    public void updateMemoryLogger(String memoryLogger) throws SecurityException {
2874        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_DEBUGGING);
2875        if(!hasAccess)
2876            throw new SecurityException("no access to change debugging settings");
2877        
2878        Element debugging=_getRootElement("debugging");
2879        if(memoryLogger.trim().length()>0)debugging.setAttribute("memory-log",memoryLogger);
2880    }*/
2881
2882    private Element _getRootElement(String name) {
2883        Element el=ConfigWebFactory.getChildByName(doc.getDocumentElement(),name);
2884        if(el==null) {
2885            el=doc.createElement(name);
2886            doc.getDocumentElement().appendChild(el);
2887        }
2888        return el;
2889    }
2890
2891    private Element _getRootElement(String name, boolean insertBefore,boolean doNotCreate) {
2892        return ConfigWebFactory.getChildByName(doc.getDocumentElement(),name,insertBefore,doNotCreate);
2893    }
2894    
2895    /**
2896     * @param setting
2897     * @param file
2898     * @param directJavaAccess
2899     * @param mail
2900     * @param datasource
2901     * @param mapping
2902     * @param customTag
2903     * @param cfxSetting
2904     * @param cfxUsage
2905     * @param debugging
2906     * @param search 
2907     * @param scheduledTasks 
2908     * @param tagExecute
2909     * @param tagImport
2910     * @param tagObject
2911     * @param tagRegistry
2912     * @throws SecurityException
2913     */
2914    public void updateDefaultSecurity(short setting, short file,Resource[] fileAccess,short directJavaAccess,
2915               short mail, short datasource, short mapping, short remote, short customTag,
2916              short cfxSetting, short cfxUsage, short debugging,
2917         short search, short scheduledTasks,
2918         short tagExecute,short tagImport, short tagObject, short tagRegistry,
2919         short cache, short gateway,short orm,
2920         short accessRead, short accessWrite) throws SecurityException {
2921        checkWriteAccess();
2922        if(!(config instanceof ConfigServer))
2923            throw new SecurityException("can't change security settings from this context");
2924        
2925        Element security=_getRootElement("security");
2926        updateSecurityFileAccess(security,fileAccess,file);
2927        security.setAttribute("setting",            SecurityManagerImpl.toStringAccessValue(setting));
2928        security.setAttribute("file",               SecurityManagerImpl.toStringAccessValue(file));
2929        security.setAttribute("direct_java_access", SecurityManagerImpl.toStringAccessValue(directJavaAccess));
2930        security.setAttribute("mail",               SecurityManagerImpl.toStringAccessValue(mail));
2931        security.setAttribute("datasource",         SecurityManagerImpl.toStringAccessValue(datasource));
2932        security.setAttribute("mapping",            SecurityManagerImpl.toStringAccessValue(mapping));
2933        security.setAttribute("remote",                 SecurityManagerImpl.toStringAccessValue(remote));
2934        security.setAttribute("custom_tag",         SecurityManagerImpl.toStringAccessValue(customTag));
2935        security.setAttribute("cfx_setting",        SecurityManagerImpl.toStringAccessValue(cfxSetting));
2936        security.setAttribute("cfx_usage",          SecurityManagerImpl.toStringAccessValue(cfxUsage));
2937        security.setAttribute("debugging",          SecurityManagerImpl.toStringAccessValue(debugging));
2938        security.setAttribute("search",             SecurityManagerImpl.toStringAccessValue(search));
2939        security.setAttribute("scheduled_task",     SecurityManagerImpl.toStringAccessValue(scheduledTasks));
2940
2941        security.setAttribute("tag_execute",        SecurityManagerImpl.toStringAccessValue(tagExecute));
2942        security.setAttribute("tag_import",         SecurityManagerImpl.toStringAccessValue(tagImport));
2943        security.setAttribute("tag_object",         SecurityManagerImpl.toStringAccessValue(tagObject));
2944        security.setAttribute("tag_registry",         SecurityManagerImpl.toStringAccessValue(tagRegistry));
2945        security.setAttribute("cache",       SecurityManagerImpl.toStringAccessValue(cache));
2946        security.setAttribute("gateway",       SecurityManagerImpl.toStringAccessValue(gateway));
2947        security.setAttribute("orm",       SecurityManagerImpl.toStringAccessValue(orm));
2948
2949        security.setAttribute("access_read",       SecurityManagerImpl.toStringAccessRWValue(accessRead));
2950        security.setAttribute("access_write",      SecurityManagerImpl.toStringAccessRWValue(accessWrite));
2951    
2952    
2953    
2954    }
2955    
2956    private void removeSecurityFileAccess(Element parent) {
2957        Element[] children = ConfigWebFactory.getChildren(parent,"file-access");
2958        
2959        // remove existing
2960        if(!ArrayUtil.isEmpty(children)){
2961                for(int i=children.length-1;i>=0;i--){
2962                        parent.removeChild(children[i]);
2963                }
2964        }
2965    }
2966    
2967    private void updateSecurityFileAccess(Element parent,Resource[] fileAccess, short file) {
2968        removeSecurityFileAccess(parent);
2969        
2970        // insert
2971        if(!ArrayUtil.isEmpty(fileAccess) && file!=SecurityManager.VALUE_ALL){
2972                Element fa;
2973                for(int i=0;i<fileAccess.length;i++){
2974                        fa=doc.createElement("file-access");
2975                        fa.setAttribute("path", fileAccess[i].getAbsolutePath());
2976                        parent.appendChild(fa);
2977                }
2978        }
2979        
2980        }
2981
2982
2983        /**
2984     * update a security manager that match the given id
2985     * @param id
2986     * @param setting
2987     * @param file
2988     * @param file_access 
2989     * @param directJavaAccess
2990     * @param mail
2991     * @param datasource
2992     * @param mapping
2993     * @param customTag
2994     * @param cfxSetting
2995     * @param cfxUsage
2996     * @param debugging
2997     * @param search 
2998     * @param scheduledTasks 
2999     * @param tagExecute
3000     * @param tagImport
3001     * @param tagObject
3002     * @param tagRegistry
3003     * @throws SecurityException
3004     * @throws ApplicationException
3005     */
3006    public void updateSecurity(String id, short setting, short file,Resource[] fileAccess, short directJavaAccess,
3007           short mail, short datasource, short mapping, short remote, short customTag,
3008          short cfxSetting, short cfxUsage, short debugging,
3009          short search, short scheduledTasks,
3010          short tagExecute,short tagImport, short tagObject, short tagRegistry, 
3011          short cache,short gateway,short orm,
3012          short accessRead, short accessWrite) throws SecurityException, ApplicationException {
3013        checkWriteAccess();
3014        if(!(config instanceof ConfigServer))
3015            throw new SecurityException("can't change security settings from this context");
3016        
3017        Element security=_getRootElement("security");
3018        Element[] children = ConfigWebFactory.getChildren(security,"accessor");
3019        Element accessor=null;
3020        for(int i=0;i<children.length;i++) {
3021            if(id.equals(children[i].getAttribute("id"))) {
3022                accessor=children[i];
3023            }
3024        }
3025        if(accessor==null) throw new ApplicationException("there is noc Security Manager for id ["+id+"]");
3026        updateSecurityFileAccess(accessor,fileAccess,file);
3027        
3028        accessor.setAttribute("setting",            SecurityManagerImpl.toStringAccessValue(setting));
3029        accessor.setAttribute("file",               SecurityManagerImpl.toStringAccessValue(file));
3030        accessor.setAttribute("direct_java_access", SecurityManagerImpl.toStringAccessValue(directJavaAccess));
3031        accessor.setAttribute("mail",               SecurityManagerImpl.toStringAccessValue(mail));
3032        accessor.setAttribute("datasource",         SecurityManagerImpl.toStringAccessValue(datasource));
3033        accessor.setAttribute("mapping",            SecurityManagerImpl.toStringAccessValue(mapping));
3034        accessor.setAttribute("remote",                 SecurityManagerImpl.toStringAccessValue(remote));
3035        accessor.setAttribute("custom_tag",         SecurityManagerImpl.toStringAccessValue(customTag));
3036        accessor.setAttribute("cfx_setting",        SecurityManagerImpl.toStringAccessValue(cfxSetting));
3037        accessor.setAttribute("cfx_usage",          SecurityManagerImpl.toStringAccessValue(cfxUsage));
3038        accessor.setAttribute("debugging",          SecurityManagerImpl.toStringAccessValue(debugging));
3039        accessor.setAttribute("search",             SecurityManagerImpl.toStringAccessValue(search));
3040        accessor.setAttribute("scheduled_task",     SecurityManagerImpl.toStringAccessValue(scheduledTasks));
3041        accessor.setAttribute("cache",     SecurityManagerImpl.toStringAccessValue(cache));
3042        accessor.setAttribute("gateway",     SecurityManagerImpl.toStringAccessValue(gateway));
3043        accessor.setAttribute("orm",     SecurityManagerImpl.toStringAccessValue(orm));
3044        
3045        accessor.setAttribute("tag_execute",        SecurityManagerImpl.toStringAccessValue(tagExecute));
3046        accessor.setAttribute("tag_import",         SecurityManagerImpl.toStringAccessValue(tagImport));
3047        accessor.setAttribute("tag_object",         SecurityManagerImpl.toStringAccessValue(tagObject));
3048        accessor.setAttribute("tag_registry",       SecurityManagerImpl.toStringAccessValue(tagRegistry));
3049
3050        accessor.setAttribute("access_read",       SecurityManagerImpl.toStringAccessRWValue(accessRead));
3051        accessor.setAttribute("access_write",      SecurityManagerImpl.toStringAccessRWValue(accessWrite));
3052    }
3053    
3054    
3055    
3056    
3057    /**
3058     * @return returns the default password
3059     * @throws SecurityException
3060     */
3061    public Password getDefaultPassword() throws SecurityException {
3062        checkReadAccess();
3063        if(config instanceof ConfigServerImpl) {
3064            return ((ConfigServerImpl)config).getDefaultPassword();
3065        }
3066        throw new SecurityException("can't access default password within this context");
3067    }
3068    /**
3069     * @param password
3070     * @throws SecurityException 
3071     * @throws IOException 
3072     * @throws DOMException 
3073     */
3074    public void updateDefaultPassword(String password) throws SecurityException, DOMException, IOException {
3075        checkWriteAccess();
3076        ((ConfigServerImpl)config).setDefaultPassword(Password.hashAndStore(doc.getDocumentElement(),password,true));
3077                
3078    }
3079
3080        public void removeDefaultPassword() throws SecurityException {
3081                checkWriteAccess();
3082        Element root=doc.getDocumentElement();
3083        Password.remove(root,true);
3084        ((ConfigServerImpl)config).setDefaultPassword(null);
3085        }
3086    
3087    /**
3088     * session type update
3089     * @param type
3090     * @throws SecurityException
3091     */
3092    public void updateSessionType(String type) throws SecurityException {
3093        checkWriteAccess();
3094        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
3095        if(!hasAccess) throw new SecurityException("no access to update scope setting");
3096        
3097        type=type.toLowerCase().trim();
3098        
3099        Element scope=_getRootElement("scope");
3100        scope.setAttribute("session-type",type);
3101    }
3102    
3103    public void updateLocalMode(String mode) throws SecurityException {
3104        checkWriteAccess();
3105        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_SETTING);
3106        if(!hasAccess) throw new SecurityException("no access to update scope setting");
3107        
3108        mode=mode.toLowerCase().trim();
3109        Element scope=_getRootElement("scope");
3110        scope.setAttribute("local-mode",mode);
3111    }
3112    
3113
3114
3115
3116        public void updateRestList(Boolean list) throws SecurityException {
3117                checkWriteAccess();
3118        boolean hasAccess=true;// TODO ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_REST);
3119        if(!hasAccess) throw new SecurityException("no access to update rest setting");
3120        
3121        
3122        Element rest=_getRootElement("rest");
3123        if(list==null) {
3124                if(rest.hasAttribute("list"))rest.removeAttribute("list");
3125        }
3126        else rest.setAttribute("list", Caster.toString(list.booleanValue()));
3127        }
3128        
3129        /*public void updateRestAllowChanges(Boolean allowChanges) throws SecurityException {
3130                checkWriteAccess();
3131        boolean hasAccess=true;// TODO ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_REST);
3132        if(!hasAccess) throw new SecurityException("no access to update rest setting");
3133        
3134        
3135        Element rest=_getRootElement("rest");
3136        if(allowChanges==null) {
3137                if(rest.hasAttribute("allow-changes"))rest.removeAttribute("allow-changes");
3138        }
3139        else rest.setAttribute("allow-changes", Caster.toString(allowChanges.booleanValue()));
3140        }*/
3141        
3142
3143    /**
3144     * updates update settingd for lucee
3145     * @param type
3146     * @param location
3147     * @throws SecurityException
3148     */
3149    public void updateUpdate(String type, String location) throws SecurityException {
3150        checkWriteAccess();
3151        
3152        if(!(config instanceof ConfigServer)) {
3153            throw new SecurityException("can't change update setting from this context, access is denied");
3154        }
3155        Element update=_getRootElement("update");
3156        update.setAttribute("type",type);
3157        try {
3158                        location=HTTPUtil.toURL(location,true).toString();
3159                } 
3160        catch (Throwable e) {
3161                ExceptionUtil.rethrowIfNecessary(e);
3162        }
3163        update.setAttribute("location",location);
3164    }
3165    
3166    /**
3167     * creates a individual security manager based on the default security manager
3168     * @param id
3169     * @throws DOMException 
3170     * @throws PageException 
3171     */
3172    public void createSecurityManager(String password,String id) throws DOMException, PageException {
3173        checkWriteAccess();
3174        ConfigServerImpl cs=(ConfigServerImpl) config.getConfigServer(password);
3175        SecurityManagerImpl dsm = (SecurityManagerImpl) cs.getDefaultSecurityManager().cloneSecurityManager();
3176        cs.setSecurityManager(id,dsm);
3177        
3178        Element security=_getRootElement("security");
3179        Element accessor=null;
3180        
3181        Element[] children = ConfigWebFactory.getChildren(security,"accessor");
3182        for(int i=0;i<children.length;i++) {
3183            if(id.equals(children[i].getAttribute("id"))) {
3184                accessor=children[i];             
3185            }
3186        }
3187        if(accessor==null) {
3188            accessor=doc.createElement("accessor");
3189            security.appendChild(accessor);
3190        }
3191        
3192        updateSecurityFileAccess(accessor,dsm.getCustomFileAccess(),dsm.getAccess(SecurityManager.TYPE_FILE));
3193        
3194        
3195        accessor.setAttribute("id",id);
3196        accessor.setAttribute("setting",            SecurityManagerImpl.toStringAccessValue(dsm.getAccess(SecurityManager.TYPE_SETTING)));
3197        accessor.setAttribute("file",               SecurityManagerImpl.toStringAccessValue(dsm.getAccess(SecurityManager.TYPE_FILE)));
3198        accessor.setAttribute("direct_java_access", SecurityManagerImpl.toStringAccessValue(dsm.getAccess(SecurityManager.TYPE_DIRECT_JAVA_ACCESS)));
3199        accessor.setAttribute("mail",               SecurityManagerImpl.toStringAccessValue(dsm.getAccess(SecurityManager.TYPE_MAIL)));
3200        accessor.setAttribute("datasource",         SecurityManagerImpl.toStringAccessValue(dsm.getAccess(SecurityManager.TYPE_DATASOURCE)));
3201        accessor.setAttribute("mapping",            SecurityManagerImpl.toStringAccessValue(dsm.getAccess(SecurityManager.TYPE_MAPPING)));
3202        accessor.setAttribute("custom_tag",         SecurityManagerImpl.toStringAccessValue(dsm.getAccess(SecurityManager.TYPE_CUSTOM_TAG)));
3203        accessor.setAttribute("cfx_setting",        SecurityManagerImpl.toStringAccessValue(dsm.getAccess(SecurityManager.TYPE_CFX_SETTING)));
3204        accessor.setAttribute("cfx_usage",          SecurityManagerImpl.toStringAccessValue(dsm.getAccess(SecurityManager.TYPE_CFX_USAGE)));
3205        accessor.setAttribute("debugging",          SecurityManagerImpl.toStringAccessValue(dsm.getAccess(SecurityManager.TYPE_DEBUGGING)));
3206        accessor.setAttribute("cache",                  SecurityManagerImpl.toStringAccessValue(dsm.getAccess(SecurityManagerImpl.TYPE_CACHE)));
3207        accessor.setAttribute("gateway",                SecurityManagerImpl.toStringAccessValue(dsm.getAccess(SecurityManagerImpl.TYPE_GATEWAY)));
3208        accessor.setAttribute("orm",                    SecurityManagerImpl.toStringAccessValue(dsm.getAccess(SecurityManagerImpl.TYPE_ORM)));
3209
3210        accessor.setAttribute("tag_execute",        SecurityManagerImpl.toStringAccessValue(dsm.getAccess(SecurityManager.TYPE_TAG_EXECUTE)));
3211        accessor.setAttribute("tag_import",         SecurityManagerImpl.toStringAccessValue(dsm.getAccess(SecurityManager.TYPE_TAG_IMPORT)));
3212        accessor.setAttribute("tag_object",         SecurityManagerImpl.toStringAccessValue(dsm.getAccess(SecurityManager.TYPE_TAG_OBJECT)));
3213        accessor.setAttribute("tag_registry",       SecurityManagerImpl.toStringAccessValue(dsm.getAccess(SecurityManager.TYPE_TAG_REGISTRY)));
3214        
3215    }
3216
3217
3218    /**
3219     * remove security manager matching given id
3220     * @param id
3221     * @throws PageException 
3222     */
3223    public void removeSecurityManager(String password,String id) throws PageException {
3224        checkWriteAccess();
3225        ((ConfigServerImpl)config.getConfigServer(password)).removeSecurityManager(id);
3226        
3227        Element security=_getRootElement("security");
3228       
3229        
3230        Element[] children = ConfigWebFactory.getChildren(security,"accessor");
3231        for(int i=0;i<children.length;i++) {
3232            if(id.equals(children[i].getAttribute("id"))) {
3233                security.removeChild(children[i]);
3234            }
3235        }
3236    }
3237
3238    /**
3239     * run update from cfml engine
3240     * @throws PageException
3241     */
3242    public void runUpdate(String password) throws PageException {
3243        checkWriteAccess();
3244        ConfigServerImpl cs = (ConfigServerImpl) config.getConfigServer(password);
3245        CFMLEngineFactory factory = cs.getCFMLEngine().getCFMLEngineFactory();
3246        synchronized(factory){
3247                try {
3248                    factory.update(cs.getPassword().password);
3249                } 
3250                catch (Exception e) {
3251                    throw Caster.toPageException(e);
3252                }
3253        }
3254        
3255    }
3256    
3257    /**
3258     * run update from cfml engine
3259     * @throws PageException
3260     */
3261    public void removeLatestUpdate(String password) throws PageException {
3262        _removeUpdate(password,true);
3263    }
3264    
3265    public void removeUpdate(String password) throws PageException {
3266        _removeUpdate(password,false);
3267    }
3268    
3269    private void _removeUpdate(String password,boolean onlyLatest) throws PageException {
3270        checkWriteAccess();
3271        ConfigServerImpl cs = (ConfigServerImpl) config.getConfigServer(password);
3272        try {
3273                CFMLEngineFactory factory = cs.getCFMLEngine().getCFMLEngineFactory();
3274                
3275                if(onlyLatest){
3276                        try{
3277                                factory.removeLatestUpdate(cs.getPassword().password);
3278                        }
3279                        catch(Throwable t)      {
3280                        ExceptionUtil.rethrowIfNecessary(t);
3281                                removeLatestUpdateOld(factory,cs.getPassword().password);
3282                        }
3283                }
3284                else factory.removeUpdate(cs.getPassword().password);
3285                
3286                
3287        } 
3288        catch (Exception e) {
3289            throw Caster.toPageException(e);
3290        }
3291    }
3292    
3293        private String getCoreExtension() {
3294        return "lco";
3295        }
3296        
3297        private boolean isNewerThan(int left, int right) {
3298        return left>right;
3299    }
3300        
3301    private boolean removeLatestUpdateOld(CFMLEngineFactory factory, String password) throws IOException, ServletException {
3302        File patchDir = new File(factory.getResourceRoot(),"patches");
3303        if(!patchDir.exists())patchDir.mkdirs();
3304        
3305        File[] patches=patchDir.listFiles(new ExtensionFilter(new String[]{"."+getCoreExtension()}));
3306        File patch=null;
3307        for(int i=0;i<patches.length;i++) {
3308                 if(patch==null || isNewerThan(lucee.loader.util.Util.toInVersion(patches[i].getName()),lucee.loader.util.Util.toInVersion(patch.getName()))) {
3309                 patch=patches[i];
3310             }
3311        }
3312        if(patch!=null && !patch.delete())patch.deleteOnExit();
3313        factory.restart(password);
3314        return true;
3315    }
3316    
3317    
3318    /*private Resource getPatchDirectory(CFMLEngine engine) throws IOException {
3319        //File f=engine.getCFMLEngineFactory().getResourceRoot();
3320        Resource res = ResourcesImpl.getFileResourceProvider().getResource(engine.getCFMLEngineFactory().getResourceRoot().getAbsolutePath());
3321        Resource pd = res.getRealResource("patches");
3322        if(!pd.exists())pd.mkdirs();
3323        return pd;
3324    }*/
3325    
3326    
3327    
3328    
3329    /**
3330     * run update from cfml engine
3331     * @throws PageException
3332     */
3333    public void restart(String password) throws PageException {
3334        checkWriteAccess();
3335        ConfigServerImpl cs = (ConfigServerImpl) config.getConfigServer(password);
3336        CFMLEngineFactory factory = cs.getCFMLEngine().getCFMLEngineFactory();
3337        synchronized(factory){
3338                try {
3339                    factory.restart(cs.getPassword().password);
3340                } 
3341                catch (Exception e) {
3342                    throw Caster.toPageException(e);
3343                }
3344        }
3345    }
3346
3347        public void updateWebCharset(String charset) throws PageException {
3348        checkWriteAccess();
3349                
3350        Element element = _getRootElement("charset");
3351                if(StringUtil.isEmpty(charset)){
3352                        if(config instanceof ConfigWeb)
3353                                element.removeAttribute("web-charset");
3354                        else
3355                                element.setAttribute("web-charset", "UTF-8");
3356                }
3357                else {
3358                        charset=checkCharset(charset);
3359                        element.setAttribute("web-charset", charset);
3360                }
3361        
3362                element = _getRootElement("regional");
3363                element.removeAttribute("default-encoding");// remove deprecated attribute
3364                
3365        }
3366
3367        public void updateResourceCharset(String charset) throws PageException {
3368        checkWriteAccess();
3369        
3370        Element element = _getRootElement("charset");
3371                if(StringUtil.isEmpty(charset)){
3372                        element.removeAttribute("resource-charset");
3373                }
3374                else {
3375                        charset=checkCharset(charset);
3376                        element.setAttribute("resource-charset", charset);
3377                        
3378                }
3379        
3380                // update charset
3381                
3382        }
3383
3384        public void updateTemplateCharset(String charset) throws PageException {
3385                
3386        checkWriteAccess();
3387        
3388        Element element = _getRootElement("charset");
3389                if(StringUtil.isEmpty(charset,true)){
3390                        element.removeAttribute("template-charset");
3391                }
3392                else {
3393                        charset=checkCharset(charset);
3394                        element.setAttribute("template-charset", charset);
3395                }
3396        }
3397        
3398        private String checkCharset(String charset)  throws PageException{
3399                charset=charset.trim();
3400                if("system".equalsIgnoreCase(charset))
3401                        charset=SystemUtil.getCharset().name();
3402                else if("jre".equalsIgnoreCase(charset))
3403                        charset=SystemUtil.getCharset().name();
3404                else if("os".equalsIgnoreCase(charset))
3405                        charset=SystemUtil.getCharset().name();
3406                
3407                // check access
3408                boolean hasAccess = ConfigWebUtil.hasAccess(config, SecurityManager.TYPE_SETTING);
3409                if(!hasAccess) {
3410                        throw new SecurityException("no access to update regional setting");
3411                }
3412                
3413                // check encoding
3414                try {
3415                        IOUtil.checkEncoding(charset);
3416                }
3417                catch (IOException e) {throw Caster.toPageException(e);}
3418                return charset;
3419        }
3420
3421
3422        private Resource getStoragDir(Config config) {
3423        Resource storageDir = config.getConfigDir().getRealResource("storage");
3424                if(!storageDir.exists())storageDir.mkdirs();
3425                return storageDir;
3426        }
3427        
3428        public void storageSet(Config config,String key, Object value) throws ConverterException, IOException, SecurityException {
3429        checkWriteAccess();
3430                Resource storageDir = getStoragDir(config);
3431                Resource storage=storageDir.getRealResource(key+".wddx");
3432                
3433                WDDXConverter converter =new WDDXConverter(config.getTimeZone(),true,true);
3434                String wddx=converter.serialize(value);
3435                IOUtil.write(storage, wddx, "UTF-8", false);
3436        }
3437
3438
3439        public Object storageGet(Config config, String key) throws ConverterException, IOException, SecurityException {
3440        checkReadAccess();
3441                Resource storageDir = getStoragDir(config);
3442                Resource storage=storageDir.getRealResource(key+".wddx");
3443                if(!storage.exists()) throw new IOException("there is no storage with name "+key);
3444                WDDXConverter converter =new WDDXConverter(config.getTimeZone(),true,true);
3445                return converter.deserialize(IOUtil.toString(storage,"UTF-8"), true);
3446        }
3447
3448
3449        public void updateCustomTagDeepSearch(boolean customTagDeepSearch) throws SecurityException {
3450                checkWriteAccess();
3451                if(!ConfigWebUtil.hasAccess(config, SecurityManager.TYPE_CUSTOM_TAG)) 
3452                        throw new SecurityException("no access to update custom tag setting");
3453                
3454                Element element = _getRootElement("custom-tag");
3455                element.setAttribute("custom-tag-deep-search",Caster.toString(customTagDeepSearch));
3456        }
3457
3458        public void resetId() throws PageException {
3459                checkWriteAccess();
3460                Resource res=config.getConfigDir().getRealResource("id");
3461                try {
3462                        if(res.exists())res.remove(false);
3463                } catch (IOException e) {
3464                        throw Caster.toPageException(e);
3465                }
3466        
3467        }
3468        
3469        public void updateCustomTagLocalSearch(boolean customTagLocalSearch) throws SecurityException {
3470                checkWriteAccess();
3471                if(!ConfigWebUtil.hasAccess(config, SecurityManager.TYPE_CUSTOM_TAG)) 
3472                        throw new SecurityException("no access to update custom tag setting");
3473                
3474                Element element = _getRootElement("custom-tag");
3475                element.setAttribute("custom-tag-local-search",Caster.toString(customTagLocalSearch));
3476        }
3477        
3478
3479
3480        public void updateCustomTagExtensions(String extensions) throws PageException {
3481                checkWriteAccess();
3482                if(!ConfigWebUtil.hasAccess(config, SecurityManager.TYPE_CUSTOM_TAG)) 
3483                        throw new SecurityException("no access to update custom tag setting");
3484                
3485                // check
3486                Array arr = ListUtil.listToArrayRemoveEmpty(extensions, ',');
3487                ListUtil.trimItems(arr);
3488                //throw new ApplicationException("you must define at least one extension");
3489                
3490                
3491                // update charset
3492                Element element = _getRootElement("custom-tag");
3493                element.setAttribute("extensions",ListUtil.arrayToList(arr, ","));
3494        }
3495
3496
3497        public void updateRemoteClient(String label,String url, String type,
3498                        String securityKey, String usage, String adminPassword, String serverUsername, String serverPassword,
3499                        String proxyServer, String proxyUsername, String proxyPassword, String proxyPort) throws PageException {
3500                checkWriteAccess();
3501                
3502                // SNSN
3503                
3504                boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManagerImpl.TYPE_REMOTE);
3505        if(!hasAccess)
3506            throw new SecurityException("no access to update remote client settings");
3507        
3508        
3509        Element clients=_getRootElement("remote-clients");
3510        
3511        if(StringUtil.isEmpty(url)) throw new ExpressionException("url can be a empty value");
3512        if(StringUtil.isEmpty(securityKey)) throw new ExpressionException("securityKey can be a empty value");
3513        if(StringUtil.isEmpty(adminPassword)) throw new ExpressionException("adminPassword can be a empty value");
3514        url=url.trim();
3515        securityKey=securityKey.trim();
3516        adminPassword=adminPassword.trim();
3517        
3518        Element[] children = ConfigWebFactory.getChildren(clients,"remote-client");
3519        
3520        // Update
3521        for(int i=0;i<children.length;i++) {
3522            Element el=children[i];
3523            String _url=el.getAttribute("url");
3524                        if(_url!=null && _url.equalsIgnoreCase(url)) {
3525                                el.setAttribute("label",label);
3526                                el.setAttribute("type",type);
3527                        el.setAttribute("usage",usage);
3528                        el.setAttribute("server-username",serverUsername);
3529                        el.setAttribute("proxy-server",proxyServer);
3530                        el.setAttribute("proxy-username",proxyUsername);
3531                        el.setAttribute("proxy-port",proxyPort);
3532                        el.setAttribute("security-key",ConfigWebFactory.encrypt(securityKey));
3533                        el.setAttribute("admin-password",ConfigWebFactory.encrypt(adminPassword));
3534                        el.setAttribute("server-password",ConfigWebFactory.encrypt(serverPassword));
3535                        el.setAttribute("proxy-password",ConfigWebFactory.encrypt(proxyPassword));
3536                        return ;
3537                        }
3538        }
3539        
3540        // Insert
3541        Element el = doc.createElement("remote-client");
3542
3543        el.setAttribute("label",label);
3544                el.setAttribute("url",url);
3545                el.setAttribute("type",type);
3546                el.setAttribute("usage",usage);
3547                el.setAttribute("server-username",serverUsername);
3548                el.setAttribute("proxy-server",proxyServer);
3549                el.setAttribute("proxy-username",proxyUsername);
3550                el.setAttribute("proxy-port",proxyPort);
3551                el.setAttribute("security-key",ConfigWebFactory.encrypt(securityKey));
3552                el.setAttribute("admin-password",ConfigWebFactory.encrypt(adminPassword));
3553                el.setAttribute("server-password",ConfigWebFactory.encrypt(serverPassword));
3554                el.setAttribute("proxy-password",ConfigWebFactory.encrypt(proxyPassword));
3555        
3556        
3557        clients.appendChild(el);
3558        }
3559
3560        public void updateMonitor(String className,String type, String name, boolean logEnabled) throws PageException {
3561                checkWriteAccess();
3562                
3563        Element parent=_getRootElement("monitoring");
3564        
3565        
3566        Element[] children = ConfigWebFactory.getChildren(parent,"monitor");
3567        Element monitor=null;
3568        // Update
3569        for(int i=0;i<children.length;i++) {
3570            Element el=children[i];
3571            String _name=el.getAttribute("name");
3572                        if(_name!=null && _name.equalsIgnoreCase(name)) {
3573                                monitor=el;
3574                                break;
3575                        }
3576        }
3577        
3578        // Insert
3579        if(monitor==null) {
3580                monitor = doc.createElement("monitor");
3581                parent.appendChild(monitor);
3582        }
3583        
3584        monitor.setAttribute("class",className);
3585        monitor.setAttribute("type",type);
3586        monitor.setAttribute("name",name);
3587        monitor.setAttribute("log",Caster.toString(logEnabled));
3588        }
3589        
3590
3591
3592
3593        public void updateExecutionLog(String className, Struct args, boolean enabled) {
3594                Element el=_getRootElement("execution-log");
3595                el.setAttribute("class",className);
3596                el.setAttribute("arguments",toStringCSSStyle(args));
3597                el.setAttribute("enabled",Caster.toString(enabled));
3598        }
3599        
3600        
3601        
3602        
3603        
3604
3605        public void removeMonitor(String name) throws PageException {
3606                checkWriteAccess();
3607                
3608        Element parent=_getRootElement("monitoring");
3609        
3610        
3611        Element[] children = ConfigWebFactory.getChildren(parent,"monitor");
3612        // Update
3613        for(int i=0;i<children.length;i++) {
3614            Element el=children[i];
3615            String _name=el.getAttribute("name");
3616                        if(_name!=null && _name.equalsIgnoreCase(name)) {
3617                                parent.removeChild(el);
3618                        }
3619        }
3620        
3621        }
3622
3623
3624        public void updateExtensionInfo(boolean enabled) {
3625                Element extensions=_getRootElement("extensions");
3626                extensions.setAttribute("enabled", Caster.toString(enabled));
3627        }
3628        
3629
3630        public void updateExtensionProvider(String strUrl) {
3631                Element extensions=_getRootElement("extensions");
3632                Element[] children = ConfigWebFactory.getChildren(extensions,"provider");
3633        strUrl=strUrl.trim();
3634        
3635        // Update
3636                Element el;
3637                String url;
3638        for(int i=0;i<children.length;i++) {
3639            el=children[i];
3640            url=el.getAttribute("url");
3641            if( url!=null && url.trim().equalsIgnoreCase(strUrl)) {
3642                                //el.setAttribute("cache-timeout",Caster.toString(cacheTimeout));
3643                                return ;
3644                        }
3645        }
3646        
3647     // Insert
3648        el = doc.createElement("provider");
3649
3650        el.setAttribute("url",strUrl);
3651        //el.setAttribute("cache-timeout",Caster.toString(cacheTimeout));
3652                
3653                XMLUtil.prependChild(extensions,el);
3654        }
3655        
3656
3657        public void removeExtensionProvider(String strUrl) {
3658                Element parent=_getRootElement("extensions");
3659                Element[] children = ConfigWebFactory.getChildren(parent,"provider");
3660                strUrl=strUrl.trim();
3661                Element child;
3662                String url;
3663        for(int i=0;i<children.length;i++) {
3664            child=children[i];
3665            url=child.getAttribute("url");
3666                        if(     url!=null && url.trim().equalsIgnoreCase(strUrl)) {
3667                                parent.removeChild(child);
3668                                return ;
3669                        }
3670        }
3671        }
3672        
3673
3674        public void updateExtension(PageContext pc,Extension extension) throws PageException {
3675                checkWriteAccess();
3676                
3677                String uid = createUid(pc,extension.getProvider(),extension.getId());
3678                
3679                Element extensions=_getRootElement("extensions");
3680                Element[] children = ConfigWebFactory.getChildren(extensions,"extension");
3681        
3682        // Update
3683                Element el;
3684                String provider,id;
3685        for(int i=0;i<children.length;i++) {
3686            el=children[i];
3687            provider=el.getAttribute("provider");
3688            id=el.getAttribute("id");
3689                        if(uid.equalsIgnoreCase(createUid(pc,provider, id))) {
3690                                setExtensionAttrs(el,extension);
3691                                return ;
3692                        }
3693        }
3694        
3695     // Insert
3696        el = doc.createElement("extension");
3697
3698                el.setAttribute("provider",extension.getProvider());
3699                el.setAttribute("id",extension.getId());
3700                setExtensionAttrs(el,extension);
3701        extensions.appendChild(el);
3702        }
3703
3704
3705        private String createUid(PageContext pc,String provider, String id) throws PageException {
3706                if(Decision.isUUId(id)) {
3707                        return Hash.invoke(pc.getConfig(),id,null,null, 1);
3708                }
3709                return Hash.invoke(pc.getConfig(),provider+id,null,null, 1);
3710        }
3711
3712
3713        private void setExtensionAttrs(Element el, Extension extension) {
3714        el.setAttribute("version",extension.getVersion());
3715        
3716        el.setAttribute("config",extension.getStrConfig());
3717        //el.setAttribute("config",new ScriptConverter().serialize(extension.getConfig()));
3718                
3719                el.setAttribute("category",extension.getCategory());
3720                el.setAttribute("description",extension.getDescription());
3721                el.setAttribute("image",extension.getImage());
3722                el.setAttribute("label",extension.getLabel());
3723                el.setAttribute("name",extension.getName());
3724
3725                el.setAttribute("author",extension.getAuthor());
3726                el.setAttribute("type",extension.getType());
3727                el.setAttribute("codename",extension.getCodename());
3728                el.setAttribute("video",extension.getVideo());
3729                el.setAttribute("support",extension.getSupport());
3730                el.setAttribute("documentation",extension.getDocumentation());
3731                el.setAttribute("forum",extension.getForum());
3732                el.setAttribute("mailinglist",extension.getMailinglist());
3733                el.setAttribute("network",extension.getNetwork());
3734                el.setAttribute("created",Caster.toString(extension.getCreated(),null));
3735
3736
3737        }
3738        
3739
3740        public void resetORMSetting() throws SecurityException {
3741                boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManagerImpl.TYPE_ORM);
3742        
3743        if(!hasAccess)
3744            throw new SecurityException("no access to update ORM Settings");
3745        
3746                
3747                
3748                Element orm=_getRootElement("orm");
3749                orm.getParentNode().removeChild(orm);
3750        }
3751        
3752
3753        public void updateORMSetting(ORMConfiguration oc) throws SecurityException {
3754                boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManagerImpl.TYPE_ORM);
3755        
3756                if(!hasAccess)
3757            throw new SecurityException("no access to update ORM Settings");
3758        
3759                
3760                
3761                Element orm=_getRootElement("orm");
3762                orm.setAttribute("autogenmap",Caster.toString(oc.autogenmap(),"true"));
3763                orm.setAttribute("event-handler",Caster.toString(oc.eventHandler(),""));
3764                orm.setAttribute("event-handling",Caster.toString(oc.eventHandling(),"false"));
3765                orm.setAttribute("naming-strategy",Caster.toString(oc.namingStrategy(),""));
3766                orm.setAttribute("flush-at-request-end",Caster.toString(oc.flushAtRequestEnd(),"true"));
3767                orm.setAttribute("cache-provider",Caster.toString(oc.getCacheProvider(),""));
3768                orm.setAttribute("cache-config",Caster.toString(oc.getCacheConfig(),"true"));
3769                orm.setAttribute("catalog",Caster.toString(oc.getCatalog(),""));
3770                orm.setAttribute("db-create",ORMConfigurationImpl.dbCreateAsString(oc.getDbCreate()));
3771                orm.setAttribute("dialect",Caster.toString(oc.getDialect(),""));
3772                orm.setAttribute("schema",Caster.toString(oc.getSchema(),""));
3773                orm.setAttribute("log-sql",Caster.toString(oc.logSQL(),"false"));
3774                orm.setAttribute("save-mapping",Caster.toString(oc.saveMapping(),"false"));
3775                orm.setAttribute("secondary-cache-enable",Caster.toString(oc.secondaryCacheEnabled(),"false"));
3776                orm.setAttribute("use-db-for-mapping",Caster.toString(oc.useDBForMapping(),"true"));
3777                orm.setAttribute("orm-config",Caster.toString(oc.getOrmConfig(),""));
3778                orm.setAttribute("sql-script",Caster.toString(oc.getSqlScript(),"true"));
3779                
3780                if(oc.isDefaultCfcLocation()) {
3781                        orm.removeAttribute("cfc-location");
3782                }
3783                else {
3784                        Resource[] locations = oc.getCfcLocations();
3785                        StringBuilder sb=new StringBuilder();
3786                        for(int i=0;i<locations.length;i++) {
3787                                if(i!=0)sb.append(",");
3788                                sb.append(locations[i].getAbsolutePath());
3789                        }
3790                        orm.setAttribute("cfc-location",sb.toString());
3791                }
3792                
3793                
3794                orm.setAttribute("sql-script",Caster.toString(oc.getSqlScript(),"true"));
3795                
3796        }
3797
3798
3799        public void removeExtension(String provider, String id) throws SecurityException {
3800                checkWriteAccess();
3801        
3802                Element extensions=_getRootElement("extensions");
3803                Element[] children = ConfigWebFactory.getChildren(extensions,"extension");
3804                Element child;
3805                String _provider, _id;
3806        for(int i=0;i<children.length;i++) {
3807            child=children[i];
3808                _provider=child.getAttribute("provider");
3809            _id=child.getAttribute("id"); 
3810                if(_provider!=null && _provider.equalsIgnoreCase(provider) && _id!=null && _id.equalsIgnoreCase(id)) {
3811                        extensions.removeChild(child);
3812                        }
3813            }
3814        }
3815        
3816        public void verifyExtensionProvider(String strUrl) throws PageException {
3817                HTTPResponse method=null;
3818                try {
3819                        URL url = HTTPUtil.toURL(strUrl+"?wsdl",true);
3820                        method = HTTPEngine.get(url, null, null, 2000,HTTPEngine.MAX_REDIRECT, null, null, null, null);
3821                } 
3822                catch (MalformedURLException e) {
3823                        throw new ApplicationException("url defintion ["+strUrl+"] is invalid");
3824                } 
3825                catch (IOException e) {
3826                        throw new ApplicationException("can't invoke ["+strUrl+"]",e.getMessage());
3827                }
3828                
3829                if(method.getStatusCode()!=200){int code=method.getStatusCode();
3830        String text=method.getStatusText();
3831        String msg=code+" "+text;
3832        throw new HTTPException(msg,null,code,text,method.getURL());
3833                }
3834                //Object o = 
3835                        CreateObject.doWebService(null, strUrl+"?wsdl");
3836                        
3837        }
3838
3839
3840        public void updateTLD(Resource resTld) throws IOException {
3841                updateLD(config.getTldFile(),resTld);
3842        }
3843        public void updateFLD(Resource resFld) throws IOException {
3844                updateLD(config.getFldFile(),resFld);
3845        }
3846        
3847        private void updateLD(Resource dir,Resource res) throws IOException {
3848                if(!dir.exists())dir.createDirectory(true);
3849        
3850        Resource file = dir.getRealResource(res.getName());
3851        if(file.length()!=res.length()){
3852                        ResourceUtil.copy(res, file);
3853                }
3854        }
3855        
3856        static void updateTLD(Config config,InputStream is,String name, boolean closeStream) throws IOException {
3857                updateLD(config.getTldFile(),is,name,closeStream);
3858        }
3859        static void updateFLD(Config config,InputStream is,String name, boolean closeStream) throws IOException {
3860                updateLD(config.getFldFile(),is,name,closeStream);
3861        }
3862        
3863        private static void updateLD(Resource dir,InputStream is,String name, boolean closeStream) throws IOException {
3864                if(!dir.exists())dir.createDirectory(true);
3865        Resource file = dir.getRealResource(name);
3866        IOUtil.copy(is, file.getOutputStream(), closeStream, true);
3867        }
3868
3869        public void removeTLD(String name) throws IOException {
3870                removeLD(config.getTldFile(),name);
3871        }
3872        
3873        public void removeTLDs(String[] names) throws IOException {
3874                if(ArrayUtil.isEmpty(names)) return;
3875                Resource file = config.getTldFile();
3876                for(int i=0;i<names.length;i++){
3877                        removeLD(file,names[i]);
3878                }
3879        }
3880
3881        public void removeFLDs(String[] names) throws IOException {
3882                if(ArrayUtil.isEmpty(names)) return;
3883                Resource file = config.getFldFile();
3884                for(int i=0;i<names.length;i++){
3885                        removeLD(file,names[i]);
3886                }
3887        }
3888
3889        public void removeFLD(String name) throws IOException {
3890                removeLD(config.getFldFile(),name);
3891        }
3892        
3893        private void removeLD(Resource dir,String name) throws IOException {
3894                if(dir.isDirectory()){
3895                        Resource[] children = dir.listResources(new MyResourceNameFilter(name));
3896                        for(int i=0;i<children.length;i++){
3897                                children[i].remove(false);
3898                        }
3899                }
3900        }
3901
3902        public void updateJar(Resource resJar) throws IOException {
3903                updateJar(config, resJar);
3904        }
3905        private static void updateJar(Config config, Resource resJar) throws IOException {
3906                Resource lib = config.getConfigDir().getRealResource("lib");
3907                if(!lib.exists())lib.mkdir();
3908        
3909                Resource fileLib = lib.getRealResource(resJar.getName());
3910                
3911                if(fileLib.length()!=resJar.length()){
3912                        IOUtil.closeEL(config.getClassLoader());
3913                        ResourceUtil.copy(resJar, fileLib);
3914                        ConfigWebFactory.reloadLib((ConfigImpl) config);
3915                }
3916        }
3917        
3918        static void updateJar(Config config, InputStream is, String name,boolean closeStream) throws IOException {
3919                Resource lib = config.getConfigDir().getRealResource("lib");
3920                if(!lib.exists())lib.mkdir();
3921        
3922                Resource fileLib = lib.getRealResource(name);
3923                
3924                IOUtil.closeEL(config.getClassLoader());
3925                IOUtil.copy(is, fileLib.getOutputStream(), closeStream, true);
3926                ConfigWebFactory.reloadLib((ConfigImpl) config);
3927        }
3928
3929        public void updateRemoteClientUsage(String code, String displayname) {
3930                Struct usage = config.getRemoteClientUsage();
3931                usage.setEL(code, displayname);
3932                
3933                Element extensions=_getRootElement("remote-clients");
3934                extensions.setAttribute("usage", toStringURLStyle(usage));              
3935                
3936        }
3937
3938        public void updateClusterClass(String classname) throws PageException {
3939                if(StringUtil.isEmpty(classname,true))
3940                        classname=ClusterNotSupported.class.getName();
3941                
3942                
3943        Class clazz=null;
3944                try {
3945                        clazz = ClassUtil.loadClass(config.getClassLoader(),classname);
3946                } catch (ClassException e) {
3947                        throw Caster.toPageException(e);
3948                }
3949                if(!Reflector.isInstaneOf(clazz,Cluster.class) && !Reflector.isInstaneOf(clazz,ClusterRemote.class))
3950                throw new ApplicationException("class ["+clazz.getName()+"] does not implement interface ["+Cluster.class.getName()+"] or ["+ClusterRemote.class.getName()+"]");   
3951                
3952
3953                Element scope=_getRootElement("scope");
3954                scope.setAttribute("cluster-class", clazz.getName());   
3955                ScopeContext.clearClusterScope();
3956        }
3957        
3958
3959        
3960        public void updateVideoExecuterClass(String classname) throws PageException {
3961                classname=classname.trim();
3962                
3963                if(StringUtil.isEmpty(classname,true))
3964                        classname=VideoExecuterNotSupported.class.getName();
3965                
3966                Class clazz=null;
3967                try {
3968                        clazz = ClassUtil.loadClass(config.getClassLoader(),classname);
3969                } catch (ClassException e) {
3970                        throw Caster.toPageException(e);
3971                }
3972                if(!Reflector.isInstaneOf(clazz,VideoExecuter.class))
3973                throw new ApplicationException("class ["+clazz.getName()+"] does not implement interface ["+VideoExecuter.class.getName()+"]");   
3974                
3975
3976                Element app=_getRootElement("video");
3977                app.setAttribute("video-executer-class", clazz.getName());      
3978        }
3979        public void updateAdminSyncClass(String classname) throws PageException {
3980                classname=classname.trim();
3981                
3982                if(StringUtil.isEmpty(classname,true))
3983                        classname=AdminSyncNotSupported.class.getName();
3984                
3985                Class clazz=null;
3986                try {
3987                        clazz = ClassUtil.loadClass(config.getClassLoader(),classname);
3988                } catch (ClassException e) {
3989                        throw Caster.toPageException(e);
3990                }
3991                if(!Reflector.isInstaneOf(clazz,AdminSync.class))
3992                throw new ApplicationException("class ["+clazz.getName()+"] does not implement interface ["+AdminSync.class.getName()+"]");   
3993                
3994
3995                Element app=_getRootElement("application");
3996                app.setAttribute("admin-sync-class", clazz.getName());  
3997        }
3998        
3999        
4000        
4001        public void removeRemoteClientUsage(String code) {
4002                Struct usage = config.getRemoteClientUsage();
4003                usage.removeEL(KeyImpl.getInstance(code));
4004                
4005                Element extensions=_getRootElement("remote-clients");
4006                extensions.setAttribute("usage", toStringURLStyle(usage));              
4007                
4008        }
4009
4010        public void removeJar(String strNames) throws IOException {
4011                removeJar(ListUtil.listToStringArray(strNames, ','));
4012        }
4013        public void removeJar(String[] names) throws IOException {
4014                if(ArrayUtil.isEmpty(names)) return;
4015                
4016                
4017                Resource lib = config.getConfigDir().getRealResource("lib");
4018                boolean changed=false;
4019                if(lib.isDirectory()){
4020                        for(int n=0;n<names.length;n++){
4021                                Resource[] children = lib.listResources(new MyResourceNameFilter(names[n].trim()));
4022                                for(int i=0;i<children.length;i++){
4023                                        try {
4024                                                changed=true;
4025                                                IOUtil.closeEL(config.getClassLoader());
4026                                                children[i].remove(false);
4027                                        } 
4028                                        catch (IOException ioe) {
4029                                                if(children[i] instanceof File)
4030                                                        ((File)children[i]).deleteOnExit();
4031                                                else{
4032                                                        ConfigWebFactory.reloadLib(this.config);
4033                                                        throw ioe;
4034                                                }
4035                                        }
4036                                }
4037                        }
4038                }
4039                if(changed){
4040                        ConfigWebFactory.reloadLib(this.config);
4041                        //new ResourceClassLoader(lib.listResources(),config.getClass().getClassLoader());
4042                }
4043        }
4044
4045        class MyResourceNameFilter implements ResourceNameFilter {
4046                private String name;
4047                public MyResourceNameFilter(String name){
4048                        this.name=name;
4049                }
4050                
4051                @Override
4052                public boolean accept(Resource parent, String name) {
4053                        return name.equals(this.name);
4054                }
4055        }
4056
4057         public void updateSerial(String serial) throws PageException {
4058                        
4059                checkWriteAccess();
4060                if(!(config instanceof ConfigServer)) {
4061                    throw new SecurityException("can't change serial number from this context, access is denied");
4062                }
4063                
4064                Element root=doc.getDocumentElement();
4065                if(!StringUtil.isEmpty(serial)){
4066                        serial=serial.trim();
4067                        if(!new SerialNumber(serial).isValid(serial))
4068                                throw new SecurityException("serial number is invalid");
4069                        root.setAttribute("serial-number",serial);
4070                }
4071                else{
4072                        try{
4073                                root.removeAttribute("serial-number");
4074                        }
4075                        catch(Throwable t){
4076                        ExceptionUtil.rethrowIfNecessary(t);
4077                    }
4078                }
4079                try{
4080                        root.removeAttribute("serial");
4081                }
4082                catch(Throwable t){
4083                ExceptionUtil.rethrowIfNecessary(t);
4084            }
4085            }
4086
4087
4088        public boolean updateLabel(String hash, String label) {
4089                // check
4090        if(StringUtil.isEmpty(hash,true))  return false;
4091        if(StringUtil.isEmpty(label,true)) return false;
4092        
4093                hash=hash.trim(); 
4094                label=label.trim();
4095        
4096        Element labels=_getRootElement("labels");
4097        
4098        // Update
4099        Element[] children = ConfigWebFactory.getChildren(labels,"label");
4100        for(int i=0;i<children.length;i++) {
4101            String h=children[i].getAttribute("id");
4102            if(h!=null) {
4103                if(h.equals(hash)) {
4104                                Element el=children[i];
4105                                if(label.equals(el.getAttribute("name"))) return false;
4106                                el.setAttribute("name",label);
4107                                return true;
4108                                }
4109            }
4110        }
4111        
4112        // Insert
4113        Element el=doc.createElement("label");
4114        labels.appendChild(el);
4115        el.setAttribute("id",hash);
4116        el.setAttribute("name",label);
4117                
4118        return true;
4119        }
4120        
4121        
4122        public void updateDebugSetting(int maxLogs) throws SecurityException {
4123                checkWriteAccess();
4124        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_DEBUGGING);
4125        if(!hasAccess)
4126            throw new SecurityException("no access to change debugging settings");
4127                
4128        
4129        Element debugging=_getRootElement("debugging");
4130        if(maxLogs==-1)
4131                debugging.removeAttribute("max-records-logged");
4132        else
4133                debugging.setAttribute("max-records-logged", Caster.toString(maxLogs));
4134        }
4135
4136
4137        public void updateDebugEntry(String type, String iprange,String label,String path,String fullname, Struct custom) throws SecurityException, IOException {
4138                checkWriteAccess();
4139        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_DEBUGGING);
4140        if(!hasAccess)
4141            throw new SecurityException("no access to change debugging settings");
4142                
4143        // leave this, this method throws a exception when ip range is not valid
4144        IPRange.getInstance(iprange);
4145        
4146                String id=MD5.getDigestAsString(label.trim().toLowerCase());
4147                type=type.trim();
4148                iprange=iprange.trim();
4149                label=label.trim();
4150                
4151        Element debugging=_getRootElement("debugging");
4152        
4153        // Update
4154        Element[] children = ConfigWebFactory.getChildren(debugging,"debug-entry");
4155        Element el=null;
4156        for(int i=0;i<children.length;i++) {
4157            String _id=children[i].getAttribute("id");
4158            if(_id!=null) {
4159                if(_id.equals(id)) {
4160                                el=children[i];
4161                                break;
4162                                }
4163            }
4164        }
4165        
4166        // Insert
4167        if(el==null) {
4168                el=doc.createElement("debug-entry");
4169                debugging.appendChild(el);
4170                el.setAttribute("id",id);
4171        }
4172        
4173
4174                el.setAttribute("type",type);
4175                el.setAttribute("iprange",iprange);
4176                el.setAttribute("label",label);
4177                el.setAttribute("path",path);
4178                el.setAttribute("fullname",fullname);
4179                el.setAttribute("custom",toStringURLStyle(custom));
4180        }
4181
4182
4183
4184
4185        public void removeDebugEntry(String id) throws SecurityException {
4186                checkWriteAccess();
4187        boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManager.TYPE_DEBUGGING);
4188        if(!hasAccess)
4189            throw new SecurityException("no access to change debugging settings");
4190
4191        
4192        Element debugging=_getRootElement("debugging");
4193        Element[] children = ConfigWebFactory.getChildren(debugging,"debug-entry");
4194        String _id;
4195        if(children.length>0) {
4196                for(int i=0;i<children.length;i++) {
4197                    Element el=children[i];
4198                    _id=el.getAttribute("id");
4199                                if(_id!=null && _id.equalsIgnoreCase(id)) {
4200                                debugging.removeChild(children[i]);
4201                                }
4202                }
4203        }
4204        }
4205
4206
4207        public void updateLoginSettings(boolean captcha, boolean rememberMe, int delay) {
4208
4209        Element login=_getRootElement("login");
4210        login.setAttribute("captcha",Caster.toString(captcha));
4211        login.setAttribute("rememberme",Caster.toString(rememberMe));
4212        login.setAttribute("delay",Caster.toString(delay));
4213                
4214        }
4215        
4216
4217
4218
4219        public void updateLogSettings(String name, Level level, String appenderClassName, Struct appenderArgs, String layoutClassName, Struct layoutArgs) throws PageException {
4220                checkWriteAccess();
4221                // TODO
4222        //boolean hasAccess=ConfigWebUtil.hasAccess(config,SecurityManagerImpl.TYPE_GATEWAY);
4223        // if(!hasAccess) throw new SecurityException("no access to update gateway entry");
4224        
4225        // check parameters
4226                name=name.trim();
4227        if(StringUtil.isEmpty(name))
4228            throw new ApplicationException("name can't be a empty value");
4229
4230        if(StringUtil.isEmpty(appenderClassName))
4231                throw new ExpressionException("you must define appender class name");
4232        if(StringUtil.isEmpty(layoutClassName))
4233                throw new ExpressionException("you must define layout class name");
4234        
4235        try {
4236                ClassUtil.loadClass(appenderClassName);
4237                ClassUtil.loadClass(layoutClassName);
4238                
4239                }
4240        catch (ClassException e) {
4241            throw Caster.toPageException(e);
4242                }
4243        
4244        Element parent=_getRootElement("logging");
4245        
4246        // Update
4247        Element[] children = ConfigWebFactory.getChildren(parent,"logger");
4248        Element el=null;
4249        for(int i=0;i<children.length;i++) {
4250            String n=children[i].getAttribute("name");
4251            if(name.equalsIgnoreCase(n)) {
4252                el=children[i];
4253                break;
4254                        }
4255          
4256        }
4257        // Insert
4258        if(el==null) {
4259                el=doc.createElement("logger");
4260                parent.appendChild(el);
4261                el.setAttribute("name",name);
4262        }
4263        
4264        // appender
4265        if(appenderClassName.equals(ConsoleAppender.class.getName())) appenderClassName="console";
4266        if(appenderClassName.equals(RollingResourceAppender.class.getName())) appenderClassName="resource";
4267        // layout
4268        if(layoutClassName.equals(PatternLayout.class.getName())) layoutClassName="pattern";
4269        if(layoutClassName.equals(ClassicLayout.class.getName())) layoutClassName="classic";
4270        if(layoutClassName.equals(HTMLLayout.class.getName())) layoutClassName="html";
4271        if(layoutClassName.equals(XMLLayout.class.getName())) layoutClassName="xml";
4272
4273        el.setAttribute("level",level.toString());
4274                el.setAttribute("appender",appenderClassName);
4275        el.setAttribute("appender-arguments",toStringCSSStyle(appenderArgs));
4276            el.setAttribute("layout",layoutClassName);
4277            el.setAttribute("layout-arguments",toStringCSSStyle(layoutArgs));
4278        }
4279
4280
4281        public void updateCompilerSettings(Boolean dotNotationUpperCase, Boolean suppressWSBeforeArg, Boolean nullSupport) throws PageException {
4282                
4283                Element element = _getRootElement("compiler");
4284                
4285        checkWriteAccess();
4286        if(dotNotationUpperCase==null){
4287                        if(element.hasAttribute("dot-notation-upper-case"))
4288                                element.removeAttribute("dot-notation-upper-case");
4289                }
4290        else {
4291                element.setAttribute("dot-notation-upper-case", Caster.toString(dotNotationUpperCase));
4292        }
4293        
4294
4295                // remove old settings
4296                if(element.hasAttribute("supress-ws-before-arg"))
4297                        element.removeAttribute("supress-ws-before-arg");
4298                
4299        if(suppressWSBeforeArg==null){
4300                        if(element.hasAttribute("suppress-ws-before-arg"))
4301                                element.removeAttribute("suppress-ws-before-arg");
4302                }
4303        else {
4304                element.setAttribute("suppress-ws-before-arg", Caster.toString(suppressWSBeforeArg));
4305        }
4306        
4307        // full null support
4308        if(nullSupport==null){
4309                        if(element.hasAttribute("full-null-support"))
4310                                element.removeAttribute("full-null-support");
4311                }
4312        else {
4313                element.setAttribute("full-null-support", Caster.toString(nullSupport));
4314        }
4315        
4316        
4317        
4318        }
4319        
4320        /*private void updatePlugin(Resource src) throws PageException, IOException {
4321        Resource srcDir = ResourceUtil.toResourceExisting(config, "zip://"+src.getAbsolutePath());
4322        if(!doAccept(srcDir))
4323                throw new ApplicationException("plugin ["+src+"] is invalid, missing one of the following files [Action.cfc,language.xml] in root, existing files are ["+lucee.runtime.type.util.ListUtil.arrayToList(srcDir.list(), ", ")+"]");
4324        
4325        String name=ResourceUtil.getName(src.getName());
4326        
4327        Resource dir = config.getConfigDir().getRealResource("context/admin/plugin");
4328        Resource trgDir = dir.getRealResource(name);
4329        if(trgDir.exists()){
4330                trgDir.remove(true);
4331        }
4332        
4333        ResourceUtil.copyRecursive(srcDir, trgDir);    
4334        store();
4335    }
4336        public static boolean doAccept(Resource res) {
4337                return res.isDirectory() && res.getRealResource("/Action.cfc").isFile() && res.getRealResource("/language.xml").isFile();
4338    }*/
4339
4340        
4341        static Resource[] updateContext(ConfigImpl config,InputStream is,String relpath, boolean closeStream) throws PageException, IOException, SAXException {
4342        //ConfigWebAdmin admin = new ConfigWebAdmin(config, null);
4343        List<Resource> filesDeployed=new ArrayList<Resource>();
4344        ConfigWebAdmin._updateContext(config, is, relpath, closeStream, filesDeployed);
4345        return filesDeployed.toArray(new Resource[filesDeployed.size()]);
4346    }
4347
4348        private static void _updateContext(Config config,InputStream is,String relpath, boolean closeStream,List<Resource> filesDeployed) throws PageException, IOException, SAXException {
4349        if(config instanceof ConfigServer) {
4350                ConfigWeb[] webs = ((ConfigServer)config).getConfigWebs();
4351                if(webs.length==0) return;
4352                if(webs.length==1) {
4353                        _updateContext(webs[0], is,relpath,closeStream,filesDeployed);
4354                        return;
4355                }
4356                try{
4357                        byte[] barr = IOUtil.toBytes(is);
4358                        for(int i=0;i<webs.length;i++){
4359                                _updateContext(webs[i], new ByteArrayInputStream(barr),relpath,true,filesDeployed);
4360                        }
4361                }
4362                finally {
4363                        if(closeStream)IOUtil.closeEL(is);
4364                }
4365                return ;
4366        }
4367                
4368        // ConfigWeb
4369        Resource trg = config.getConfigDir().getRealResource("context").getRealResource(relpath);
4370        if(trg.exists()) trg.remove(true);
4371        Resource p = trg.getParentResource();
4372        if(!p.isDirectory()) p.createDirectory(true); 
4373        IOUtil.copy(is, trg.getOutputStream(false), closeStream,true);
4374        filesDeployed.add(trg);
4375        _store((ConfigImpl)config);
4376    }
4377        public boolean removeContext(Config config, boolean store,String... relpathes) throws PageException, IOException, SAXException {
4378                if(ArrayUtil.isEmpty(relpathes)) return false;
4379                boolean force=false;
4380                for(int i=0;i<relpathes.length;i++){
4381                        if(_removeContext(config, relpathes[i],store))
4382                                force=true;
4383                }
4384                return force;
4385        }
4386        
4387        private boolean _removeContext(Config config,String relpath, boolean _store) throws PageException, IOException, SAXException {
4388        
4389                if(config instanceof ConfigServer) {
4390                        ConfigServer cs = ((ConfigServer)config);
4391                
4392                        // remove files from deploy folder
4393                        Resource deploy = cs.getConfigDir().getRealResource("web-context-deployment");
4394                Resource trg = deploy.getRealResource(relpath);
4395                
4396                if(trg.exists()) {
4397                        trg.remove(true);
4398                        ResourceUtil.removeEmptyFolders(deploy,null);
4399                }
4400                
4401                        // remove files from lucee web context
4402                        boolean store=false;
4403                        ConfigWeb[] webs = cs.getConfigWebs();
4404                for(int i=0;i<webs.length;i++){
4405                        if(_removeContext(webs[i], relpath,_store)) {
4406                                store=true;
4407                        }
4408                }
4409                return store;
4410        }
4411                
4412        // ConfigWeb
4413                Resource context = config.getConfigDir().getRealResource("context");
4414        Resource trg = context.getRealResource(relpath);
4415        if(trg.exists()) {
4416                trg.remove(true);
4417                if(_store) ConfigWebAdmin._store((ConfigImpl) config);
4418                ResourceUtil.removeEmptyFolders(context,null);
4419                return true;
4420        }
4421        return false;
4422    }
4423
4424        static Resource[] updateApplication(ConfigImpl config,InputStream is,String relpath, boolean closeStream) throws PageException, IOException, SAXException {
4425        ConfigWebAdmin admin = new ConfigWebAdmin(config, null);
4426        List<Resource> filesDeployed=new ArrayList<Resource>();
4427        admin._updateApplication(config, is, relpath, closeStream, filesDeployed);
4428        return filesDeployed.toArray(new Resource[filesDeployed.size()]);
4429    }
4430
4431        private void _updateApplication(Config config,InputStream is,String relpath, boolean closeStream,List<Resource> filesDeployed) throws PageException, IOException, SAXException {
4432        if(config instanceof ConfigServer) {
4433                ConfigWeb[] webs = ((ConfigServer)config).getConfigWebs();
4434                if(webs.length==0) return;
4435                if(webs.length==1) {
4436                        _updateApplication(webs[0], is,relpath,closeStream,filesDeployed);
4437                        return;
4438                }
4439                try{
4440                        byte[] barr = IOUtil.toBytes(is);
4441                        for(int i=0;i<webs.length;i++){
4442                                _updateApplication(webs[i], new ByteArrayInputStream(barr),relpath,true,filesDeployed);
4443                        }
4444                }
4445                finally {
4446                        if(closeStream)IOUtil.closeEL(is);
4447                }
4448                return ;
4449        }
4450                
4451        // ConfigWeb
4452        
4453        
4454        Resource trg = config.getRootDirectory().getRealResource(relpath);
4455        if(trg.exists()) trg.remove(true);
4456        Resource p = trg.getParentResource();
4457        if(!p.isDirectory()) p.createDirectory(true); 
4458        IOUtil.copy(is, trg.getOutputStream(false), closeStream,true);
4459        filesDeployed.add(trg);
4460        //_store((ConfigImpl)config);
4461    }
4462
4463        private void removeApplications(Config config,String[] relpathes) throws PageException, IOException, SAXException {
4464                if(ArrayUtil.isEmpty(relpathes)) return;
4465                for(int i=0;i<relpathes.length;i++){
4466                        removeApplication(config, relpathes[i]);
4467                }
4468        }
4469        
4470        private void removeApplication(Config config,String relpath) throws PageException, IOException, SAXException {
4471        if(config instanceof ConfigServer) {
4472                ConfigWeb[] webs = ((ConfigServer)config).getConfigWebs();
4473                        for(int i=0;i<webs.length;i++){
4474                                removeApplication(webs[i], relpath);
4475                }
4476                
4477                return ;
4478        }
4479                
4480        // ConfigWeb
4481        Resource trg = config.getRootDirectory().getRealResource(relpath);
4482        if(trg.exists()) trg.remove(true);
4483    }
4484        
4485        public static void removeRHExtension(ConfigImpl config,String extensionID) throws SAXException, IOException, PageException {
4486                ConfigWebAdmin admin = new ConfigWebAdmin(config, null);
4487                boolean storeChildren = admin._removeExtension(config, extensionID);
4488                admin._store();
4489                
4490                if(storeChildren && config instanceof ConfigServer) {
4491                        ConfigServer cs = (ConfigServer)config;
4492                        ConfigWeb[] webs = cs.getConfigWebs();
4493                        for(int i=0;i<webs.length;i++) {
4494                                admin._store((ConfigImpl)webs[i]);
4495                        }
4496                }
4497        }
4498
4499
4500        public boolean _removeExtension(ConfigImpl config,String extensionID) throws IOException, PageException, SAXException {
4501                if(!Decision.isUUId(extensionID)) throw new IOException("id ["+extensionID+"] is invalid, it has to be a UUID"); 
4502                
4503                Element extensions=_getRootElement("extensions");
4504                Element[] children = ConfigWebFactory.getChildren(extensions,"rhextension");// LuceeHandledExtensions
4505        
4506        // Update
4507                Element el;
4508                String id;
4509                String[] arr;
4510                boolean storeChildren=false;
4511        for(int i=0;i<children.length;i++) {
4512            el=children[i];
4513            id=el.getAttribute("id");
4514                        if(extensionID.equalsIgnoreCase(id)) {
4515                                
4516                                // jars
4517                                arr=_removeExtensionCheckOtherUsage(children,el,"jars");
4518                                removeJar(arr);
4519                                // flds
4520                                arr=_removeExtensionCheckOtherUsage(children,el,"flds");
4521                                removeFLDs(arr);
4522                                // tlds
4523                                arr=_removeExtensionCheckOtherUsage(children,el,"tlds");
4524                                removeTLDs(arr);
4525                                // contexts
4526                                arr=_removeExtensionCheckOtherUsage(children,el,"contexts");
4527                                storeChildren=removeContext(config,false, arr);
4528                                // applications
4529                                arr=_removeExtensionCheckOtherUsage(children,el,"applications");
4530                                removeApplications(config, arr);
4531                                
4532                                
4533                                
4534                                extensions.removeChild(el);
4535                                return storeChildren;
4536                        }
4537        }
4538                return false;
4539        }
4540        
4541        private String[] _removeExtensionCheckOtherUsage(Element[] children, Element curr,String type) {
4542                String currVal=curr.getAttribute(type);
4543                if(StringUtil.isEmpty(currVal)) return null;
4544                
4545                String otherVal;
4546                Element other;
4547                Set<String> currSet = ListUtil.toSet(ListUtil.trimItems(ListUtil.listToStringArray(currVal, ',')));
4548                String[] otherArr;
4549                for(int i=0;i<children.length;i++) {
4550                        other=children[i];
4551                        if(other==curr) continue;
4552                        otherVal=other.getAttribute(type);
4553                        if(StringUtil.isEmpty(otherVal)) continue;
4554                        otherArr=ListUtil.trimItems(ListUtil.listToStringArray(otherVal, ','));
4555                        for(int y=0;y<otherArr.length;y++) {
4556                                currSet.remove(otherArr[y]);
4557                        }
4558                }
4559                return currSet.toArray(new String[currSet.size()]);
4560        }
4561
4562
4563        public static void updateRHExtension(ConfigImpl config,RHExtension rhExtension) throws SAXException, IOException, PageException {
4564                ConfigWebAdmin admin = new ConfigWebAdmin(config, null);
4565                admin._updateExtension(config, rhExtension);
4566                admin._store();
4567        }
4568
4569
4570        public void _updateExtension(ConfigImpl config,RHExtension ext) throws IOException {
4571                if(!Decision.isUUId(ext.getId())) throw new IOException("id ["+ext.getId()+"] is invalid, it has to be a UUID"); 
4572                
4573                Element extensions=_getRootElement("extensions");
4574                Element[] children = ConfigWebFactory.getChildren(extensions,"rhextension");// LuceeHandledExtensions
4575        
4576        // Update
4577                Element el;
4578                String provider,id;
4579        for(int i=0;i<children.length;i++) {
4580            el=children[i];
4581            provider=el.getAttribute("provider");
4582            id=el.getAttribute("id");
4583                        if(ext.getId().equalsIgnoreCase(id)) {
4584                                setExtensionAttrs(el,ext);
4585                                return ;
4586                        }
4587        }
4588        
4589     // Insert
4590        el = doc.createElement("rhextension");
4591        setExtensionAttrs(el,ext);
4592                extensions.appendChild(el);
4593        
4594        }
4595
4596
4597        private void setExtensionAttrs(Element el, RHExtension ext) {
4598                setAttr(el,"id", ext.getId());
4599                setAttr(el,"name", ext.getName());
4600                setAttr(el,"version", ext.getVersion());
4601                setAttr(el,"jars",ListUtil.arrayToList(ext.getJars(), ","));
4602                setAttr(el,"flds",ListUtil.arrayToList(ext.getFlds(), ","));
4603                setAttr(el,"tlds",ListUtil.arrayToList(ext.getTlds(), ","));
4604                setAttr(el,"contexts",ListUtil.arrayToList(ext.getContexts(), ","));
4605                setAttr(el,"applications",ListUtil.arrayToList(ext.getApplications(), ","));    
4606        }
4607
4608
4609        private void setAttr(Element el, String name, String value) {
4610                if(value==null) value="";
4611                el.setAttribute(name, value);
4612        }
4613
4614
4615        public void updateAuthKey(String key) throws PageException {
4616                checkWriteAccess();
4617                key=key.trim();
4618                
4619                // merge new key and existing
4620                ConfigServerImpl cs=(ConfigServerImpl) config;
4621                String[] keys = cs.getAuthenticationKeys();
4622                Set<String> set=new HashSet<String>();
4623                for(int i=0;i<keys.length;i++){
4624                        set.add(keys[i]);
4625                }
4626                set.add(key);
4627                
4628                
4629                Element root=doc.getDocumentElement();
4630        root.setAttribute("auth-keys",authKeysAsList(set));
4631                
4632                
4633        }
4634
4635        public void removeAuthKeys(String key) throws PageException {
4636                checkWriteAccess();
4637                key=key.trim();
4638                
4639                // remove key
4640                ConfigServerImpl cs=(ConfigServerImpl) config;
4641                String[] keys = cs.getAuthenticationKeys();
4642                Set<String> set=new HashSet<String>();
4643                for(int i=0;i<keys.length;i++){
4644                        if(!key.equals(keys[i]))set.add(keys[i]);
4645                }
4646
4647                Element root=doc.getDocumentElement();
4648        root.setAttribute("auth-keys",authKeysAsList(set));
4649        }
4650
4651        public void updateAPIKey(String key) throws SecurityException, ApplicationException {
4652                checkWriteAccess();
4653                key=key.trim();
4654                if(!Decision.isGUId(key))
4655                        throw new ApplicationException("passed API Key ["+key+"] is not valid");
4656                Element root=doc.getDocumentElement();
4657        root.setAttribute("api-key",key);
4658                
4659        }
4660        
4661        public void removeAPIKey() throws PageException {
4662                checkWriteAccess();
4663                Element root=doc.getDocumentElement();
4664        if(root.hasAttribute("api-key"))
4665                root.removeAttribute("api-key");
4666        }
4667
4668        private String authKeysAsList(Set<String> set) throws PageException {
4669                StringBuilder sb=new StringBuilder();
4670                Iterator<String> it = set.iterator();
4671                String key;
4672                while(it.hasNext()){
4673                        key=it.next().trim();
4674                        if(sb.length()>0)sb.append(',');
4675                        try {
4676                                sb.append(URLEncoder.encode(key, "UTF-8"));
4677                        }
4678                        catch (UnsupportedEncodingException e) {
4679                                throw Caster.toPageException(e);
4680                        }
4681                }
4682                return sb.toString();
4683        }
4684}