]> err.no Git - sope/blob - sope-appserver/NGObjWeb/WOScriptedComponent.m
use %p for pointer formats, fixed gcc 4.1 warnings, minor code improvs
[sope] / sope-appserver / NGObjWeb / WOScriptedComponent.m
1 /*
2   Copyright (C) 2000-2005 SKYRIX Software AG
3
4   This file is part of SOPE.
5
6   SOPE is free software; you can redistribute it and/or modify it under
7   the terms of the GNU Lesser General Public License as published by the
8   Free Software Foundation; either version 2, or (at your option) any
9   later version.
10
11   SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12   WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14   License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with SOPE; see the file COPYING.  If not, write to the
18   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19   02111-1307, USA.
20 */
21
22 #include "WOScriptedComponent.h"
23 #include <NGObjWeb/WOTemplateBuilder.h>
24 #include <NGScripting/NGScriptLanguage.h>
25 #include "common.h"
26
27 @interface NSObject(misc)
28 - (void)applyStandardClasses;
29 - (BOOL)isScriptFunction;
30
31 - (id)callScriptFunction:(NSString *)_name withObject:(id)_arg0;
32 - (id)evaluateScript:(NSString *)_script source:(NSString *)_s line:(int)_line;
33
34 @end
35
36 @interface WOComponent(UsedPrivates)
37 - (id)initWithName:(NSString *)_cname
38   template:(WOTemplate *)_template
39   inContext:(WOContext *)_ctx;
40 @end
41
42 @interface WOComponentScript(UsedPrivates)
43 - (id)initScriptWithComponent:(id)_comp;
44 @end
45
46 @implementation WOScriptedComponent
47
48 static BOOL logScriptKVC     = NO;
49 static BOOL logScriptInit    = NO;
50 static BOOL logScriptDealloc = NO;
51
52 + (void)initialize {
53   static BOOL didInit = NO;
54   if (!didInit) {
55     NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
56     didInit = YES;
57     logScriptKVC     = [ud boolForKey:@"WOLogScriptKVC"];
58     logScriptInit    = [ud boolForKey:@"WOLogScriptInit"];
59     logScriptDealloc = [ud boolForKey:@"WOLogScriptDealloc"];
60   }
61 }
62
63 - (id)initWithName:(NSString *)_cname
64   template:(WOTemplate *)_template
65   inContext:(WOContext *)_ctx
66 {
67   if ((self = [super initWithName:_cname template:_template inContext:_ctx])) {
68     self->script = [[_template componentScript] retain];
69
70     self->language = 
71       [[NGScriptLanguage languageWithName:[self->script language]] retain];
72     if (self->language == nil) {
73       [self logWithFormat:
74               @"did not find engine for script language %@", 
75               [self->script language]];
76       RELEASE(self);
77       return nil;
78     }
79     
80     if ((self->shadow = [self->language createShadowForMaster:self]) == nil) {
81       [self logWithFormat:
82               @"could not create shadow for component in language %@", 
83               self->language];
84       RELEASE(self);
85       return nil;
86     }
87     
88     if ([self->shadow respondsToSelector:@selector(applyStandardClasses)])
89       [(id)self->shadow applyStandardClasses];
90     
91     [self->script initScriptWithComponent:self];
92     
93     if (logScriptInit)
94       [self logWithFormat:@"created scripted component: %@", self];
95   }
96   return self;
97 }
98
99 - (void)dealloc {
100   if (logScriptDealloc)
101     [self logWithFormat:@"will dealloc scripted component: %@", self];
102   
103   [self->shadow invalidateShadow]; /* ensure shadow is dead ;-) */
104   RELEASE(self->shadow);
105   RELEASE(self->language);
106   RELEASE(self->script);
107   RELEASE(self->template);
108   [super dealloc];
109 }
110
111 /* accessors */
112
113 - (void)setTemplate:(id)_template {
114   ASSIGN(self->template, _template);
115 }
116 - (WOElement *)_woComponentTemplate {
117   return self->template;
118 }
119
120 - (BOOL)isScriptedComponent {
121   return YES;
122 }
123
124 /* scripting */
125
126 - (id)evaluateScript:(NSString *)_script language:(NSString *)_lang 
127   source:(NSString *)_src line:(unsigned)_line
128 {
129   return [self->shadow evaluateScript:_script source:_src line:_line];
130 }
131
132 /* notification mapping */
133
134 - (void)awake {
135   [super awake];
136   
137   if ([self->shadow hasFunctionNamed:@"awake"])
138     [self->shadow callScriptFunction:@"awake"];
139 }
140 - (void)sleep {
141   if ([self->shadow hasFunctionNamed:@"sleep"])
142     [self->shadow callScriptFunction:@"sleep"];
143   
144   //[self debugWithFormat:@"vars: %@", [self variableDictionary]];
145   [super sleep];
146 }
147
148 /* script properties */
149
150 - (BOOL)takeValue:(id)_value forJSPropertyNamed:(NSString *)_key {
151   NSAssert1(self->shadow, @"missing shadow for component %@", self);
152   [self->shadow setObject:_value forKey:_key];
153   return YES;
154 }
155 - (id)valueForJSPropertyNamed:(NSString *)_key {
156   [self debugWithFormat:@"value for prop %@", _key];
157   NSAssert1(self->shadow, @"missing shadow for component %@", self);
158   return [self->shadow objectForKey:_key];
159 }
160
161 /* extra variables */
162
163 - (void)setObject:(id)_obj forKey:(NSString *)_key {
164   //[self debugWithFormat:@"setObject:%@ forKey:%@", _obj, _key];
165   NSAssert1(self->shadow, @"missing shadow for component %@", self);
166   [self->shadow setObject:_obj forKey:_key];
167 }
168 - (id)objectForKey:(NSString *)_key {
169   NSAssert1(self->shadow, @"missing shadow for component %@", self);
170   return [self->shadow objectForKey:_key];
171 }
172
173 /* key-value coding */
174
175 - (void)takeValue:(id)_value forKey:(NSString *)_key {
176   NSString *funcName;
177   id       func;
178   unsigned len;
179   unsigned char *buf;
180   
181   len = [_key cStringLength];
182   buf = malloc(len + 4);
183   [_key getCString:&(buf[3])];
184   buf[0] = 's'; buf[1] = 'e'; buf[2] = 't';
185   buf[len + 3] = '\0';
186   if (len > 0) buf[3] = toupper(buf[3]);
187   funcName = [NSString stringWithCString:buf length:(len + 3)];
188   free(buf);
189   
190   if ((func = [self->shadow objectForKey:funcName])) {
191     if ([func isScriptFunction]) {
192       id result;
193       
194       if (logScriptKVC) {
195         [self logWithFormat:@"KVC: for key %@ call %@(%@)", 
196                 _key, funcName, _value];
197       }
198       
199       result = [self->shadow callScriptFunction:funcName withObject:_value];
200     }
201     else {
202       [self logWithFormat:
203               @"KVC: object stored at '%@' is not a function, "
204               @"could not set value for key %@ !",
205               funcName, _key];
206     }
207   }
208   else {
209     if (logScriptKVC) {
210       [self logWithFormat:@"KVC: assign %@=%@ (no func '%@')", 
211               _key, _value, funcName];
212     }
213     
214     [self->shadow setObject:_value forKey:_key];
215   }
216 }
217
218 - (id)valueForKey:(NSString *)_key {
219   id obj;
220   
221   //[self logWithFormat:@"script: valueForKey:%@", _key];
222   
223   if ((obj = [self->shadow objectForKey:_key])) {
224     if ([obj isScriptFunction]) {
225       if (logScriptKVC) {
226         [self logWithFormat:@"KVC: for key %@ call %@", 
227                 _key, _key];
228       }
229       obj = [self->shadow callScriptFunction:_key];
230     }
231     else {
232       if (logScriptKVC) {
233         [self logWithFormat:@"KVC: valueForKey(%@): %@", 
234                 _key, obj];
235       }
236     }
237     return obj;
238   }
239   else {
240     if (logScriptKVC) {
241       [self logWithFormat:@"KVC: get value for key %@ from WOComponent", 
242               _key];
243     }
244     return [super valueForKey:_key];
245   }
246 }
247
248 /* logging */
249
250 - (NSString *)loggingPrefix {
251   return [NSString stringWithFormat:@"script<%@>[0x%p]", [self name], self];
252 }
253
254 @end /* WOScriptedComponent */
255
256 @implementation NSObject(ScriptFunc)
257
258 - (BOOL)isScriptFunction {
259   return NO;
260 }
261
262 @end /* NSObject(ScriptFunc) */