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.type;
020
021import java.io.IOException;
022import java.io.ObjectInput;
023import java.io.ObjectOutput;
024
025import lucee.runtime.ComponentImpl;
026import lucee.runtime.PageContext;
027import lucee.runtime.dump.DumpData;
028import lucee.runtime.dump.DumpProperties;
029import lucee.runtime.engine.ThreadLocalPageContext;
030import lucee.runtime.exp.PageException;
031import lucee.runtime.type.scope.ClosureScope;
032import lucee.runtime.type.scope.Variables;
033import lucee.runtime.type.util.ComponentUtil;
034import lucee.runtime.type.util.KeyConstants;
035import lucee.runtime.type.util.UDFUtil;
036
037public class Closure extends UDFImpl {
038        
039        
040
041        private static final long serialVersionUID = -7200106903813254844L; // do not change
042        
043        private Variables variables;
044
045
046        public Closure(){
047                super();
048        }
049
050        public Closure(UDFProperties properties) {
051                super(properties);
052                PageContext pc = ThreadLocalPageContext.get();
053                if(pc.undefinedScope().getCheckArguments())
054                        this.variables=new ClosureScope(pc,pc.argumentsScope(),pc.localScope(),pc.variablesScope());
055                else{
056                        this.variables=pc.variablesScope();
057                        variables.setBind(true);
058                }
059        }
060        
061        public Closure(UDFProperties properties, Variables variables) {
062                super(properties);
063                this.variables=variables;
064                
065        }
066
067        @Override
068        public UDF duplicate(ComponentImpl c) {
069                Closure clo = new Closure(properties,variables);// TODO duplicate variables as well?
070                clo.ownerComponent=c;
071                clo.setAccess(getAccess());
072                return clo;
073        }
074
075        @Override
076        public Object callWithNamedValues(PageContext pc,Collection.Key calledName, Struct values, boolean doIncludePath) throws PageException {
077                Variables parent=pc.variablesScope();
078        try{
079                pc.setVariablesScope(variables);
080                return super.callWithNamedValues(pc, calledName,values, doIncludePath);
081                }
082                finally {
083                        pc.setVariablesScope(parent);
084                }
085        }
086        
087        @Override
088        public Object callWithNamedValues(PageContext pc, Struct values, boolean doIncludePath) throws PageException {
089                Variables parent=pc.variablesScope();
090        try{
091                pc.setVariablesScope(variables);
092                return super.callWithNamedValues(pc, values, doIncludePath);
093                }
094                finally {
095                        pc.setVariablesScope(parent);
096                }
097        }
098
099        @Override
100        public Object call(PageContext pc,Collection.Key calledName, Object[] args, boolean doIncludePath) throws PageException {
101                Variables parent=pc.variablesScope();
102                try{
103                pc.setVariablesScope(variables);
104                        return super.call(pc, calledName, args, doIncludePath);
105                }
106                finally {
107                        pc.setVariablesScope(parent);
108                }
109        }
110
111        @Override
112        public Object call(PageContext pc, Object[] args, boolean doIncludePath) throws PageException {
113                Variables parent=pc.variablesScope();
114                try{
115                pc.setVariablesScope(variables);
116                        return super.call(pc, args, doIncludePath);
117                }
118                finally {
119                        pc.setVariablesScope(parent);
120                }
121        }
122
123        @Override
124        public DumpData toDumpData(PageContext pageContext, int maxlevel,DumpProperties dp) {
125                return UDFUtil.toDumpData(pageContext, maxlevel, dp,this,UDFUtil.TYPE_CLOSURE);
126        }
127
128        @Override
129        public Struct getMetaData(PageContext pc) throws PageException {
130                Struct meta = ComponentUtil.getMetaData(pc, properties);
131                meta.setEL(KeyConstants._closure, Boolean.TRUE);// MUST move this to class UDFProperties
132                meta.setEL("ANONYMOUSCLOSURE", Boolean.TRUE);// MUST move this to class UDFProperties
133                
134                return meta;
135        }
136
137        public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
138                // access
139                setAccess(in.readInt());
140                
141                // properties
142                properties=(UDFPropertiesImpl) in.readObject();
143        }
144
145
146        public void writeExternal(ObjectOutput out) throws IOException {
147                // access
148                out.writeInt(getAccess());
149                
150                // properties
151                out.writeObject(properties);
152        }
153}