Skip to content

Commit 21357a2

Browse files
committed
Merge branch '7.1' into 7.2
# Conflicts: # core/src/main/java/lucee/runtime/config/ConfigImpl.java # loader/build.xml # loader/pom.xml
2 parents 0190ef9 + d925bf6 commit 21357a2

File tree

72 files changed

+2829
-519
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+2829
-519
lines changed

core/src/main/java/lucee/runtime/CFMLFactoryImpl.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -341,8 +341,9 @@ public void checkTimeout() {
341341
if (pc == null) continue;
342342
long timeout = pc.getRequestTimeout();
343343
Thread th;
344-
// reached timeout
345-
if (pc.getStartTime() + timeout < System.currentTimeMillis() && Long.MAX_VALUE != timeout) {
344+
// reached timeout (adjusted for debugger suspend time)
345+
long suspendedMillis = pc.getDebuggerTotalSuspendedMillis();
346+
if (pc.getStartTime() + timeout + suspendedMillis < System.currentTimeMillis() && Long.MAX_VALUE != timeout) {
346347
Log log = ThreadLocalPageContext.getLog(pc, "requesttimeout");
347348
if (reachedConcurrentReqThreshold() && reachedMemoryThreshold() && reachedCPUThreshold()) {
348349
if (log != null) {

core/src/main/java/lucee/runtime/ComponentImpl.java

Lines changed: 86 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ public final class ComponentImpl extends StructSupport implements Externalizable
145145
ComponentImpl top = this;
146146
ComponentImpl base;
147147
private PageSource pageSource;
148-
private ComponentPageRef cpRef;
148+
private ComponentPageImpl cp;
149149
private ComponentScope scope;
150150

151151
// for all the same
@@ -179,7 +179,8 @@ public final class ComponentImpl extends StructSupport implements Externalizable
179179
/**
180180
* Constructor of the Component, USED ONLY FOR DESERIALIZE
181181
*/
182-
public ComponentImpl() {}
182+
public ComponentImpl() {
183+
}
183184

184185
/**
185186
* constructor of the class
@@ -207,7 +208,7 @@ public ComponentImpl(ComponentPageImpl componentPage, Boolean output, boolean _s
207208
this.properties = new ComponentProperties(componentPage.getComponentName(), dspName, extend.trim(), implement, hint, output, callPath + appendix, realPath,
208209
componentPage.getSubname(), _synchronized, null, persistent, accessors, modifier, meta);
209210

210-
this.cpRef = new ComponentPageRef(componentPage);
211+
this.cp = componentPage;
211212
this.pageSource = componentPage.getPageSource();
212213
this.importDefintions = componentPage.getImportDefintions();
213214
// if(modifier!=0)
@@ -217,17 +218,11 @@ public ComponentImpl(ComponentPageImpl componentPage, Boolean output, boolean _s
217218
}
218219

219220
public JavaSettings getJavaSettings(PageContext pc) throws IOException {
220-
ComponentPageImpl cp;
221-
try {
222-
cp = this.cpRef.get(pc);
223-
}
224-
catch (PageException e) {
225-
throw ExceptionUtil.toIOException(e);
226-
}
227-
boolean is = cp.isJavaSettingsInitialized();
221+
222+
boolean is = this.cp.isJavaSettingsInitialized();
228223
if (!is) {
229224
synchronized (cp) {
230-
is = cp.isJavaSettingsInitialized();
225+
is = this.cp.isJavaSettingsInitialized();
231226
if (!is) {
232227
boolean mergeConfig = false;
233228
JavaSettings js = null;
@@ -270,18 +265,12 @@ public JavaSettings getJavaSettings(PageContext pc) throws IOException {
270265
// current
271266
js = JavaSettingsImpl.merge(pc.getConfig(), js, JavaSettingsImpl.readJavaSettings(pc, properties.meta));
272267
if (mergeConfig) js = JavaSettingsImpl.merge(pc.getConfig(), ((ConfigPro) pc.getConfig()).getJavaSettings(), js);
273-
;
274268

275-
return cp.setJavaSettings(js);
269+
return this.cp.setJavaSettings(js);
276270
}
277271
}
278272
}
279-
return cp.getJavaSettings();
280-
}
281-
282-
@Override
283-
public final int hashCode() {
284-
return java.util.Objects.hash(base, _data, pageSource);
273+
return this.cp.getJavaSettings();
285274
}
286275

287276
public boolean hasJavaSettings(PageContext pc) {
@@ -311,7 +300,7 @@ public ComponentImpl _duplicate(boolean deepCopy, boolean isTop) {
311300
try {
312301
// attributes
313302
trg.pageSource = pageSource;
314-
trg.cpRef = cpRef;
303+
trg.cp = cp;
315304
// trg._triggerDataMember=_triggerDataMember;
316305
trg.useShadow = useShadow;
317306
trg._static = _static;
@@ -485,7 +474,7 @@ public void init(PageContext pageContext, ComponentPageImpl componentPage, boole
485474

486475
if (base != null) {
487476
this.dataMemberDefaultAccess = base.dataMemberDefaultAccess;
488-
this._static = new StaticScope(base._static, this, cpRef, dataMemberDefaultAccess);
477+
this._static = new StaticScope(base._static, this, new ComponentPageRef(componentPage), dataMemberDefaultAccess);
489478
this.absFin = base.absFin;
490479
_data = base._data;
491480
_udfs = isRestEnabled ? new LinkedHashMap<Key, UDF>(base._udfs) : new HashMap<Key, UDF>(base._udfs);
@@ -496,7 +485,7 @@ public void init(PageContext pageContext, ComponentPageImpl componentPage, boole
496485
}
497486
else {
498487
this.dataMemberDefaultAccess = pageContext.getConfig().getComponentDataMemberDefaultAccess();
499-
this._static = new StaticScope(null, this, cpRef, dataMemberDefaultAccess);
488+
this._static = new StaticScope(null, this, new ComponentPageRef(componentPage), dataMemberDefaultAccess);
500489
// TODO get per CFC setting
501490
// this._triggerDataMember=pageContext.getConfig().getTriggerComponentDataMember();
502491
_udfs = isRestEnabled ? new LinkedHashMap<Key, UDF>() : new HashMap<Key, UDF>();
@@ -511,7 +500,7 @@ public void init(PageContext pageContext, ComponentPageImpl componentPage, boole
511500

512501
long indexBase = 0;
513502
if (base != null) {
514-
indexBase = base.cpRef.get(pageContext).getStaticStruct().index();
503+
indexBase = base.cp.getStaticStruct().index();
515504
}
516505

517506
// scope
@@ -759,8 +748,7 @@ else if (_namedArgs != null) {
759748
return Reflector.componentToClass(pc, this).getClass();
760749
}
761750

762-
// When calling via super, use public access for error message since super calls should access
763-
// inherited methods
751+
// When calling via super, use public access for error message since super calls should access inherited methods
764752
int errorAccess = superAccess ? ACCESS_PUBLIC : access;
765753
if (member == null) throw ComponentUtil.notFunction(this, KeyImpl.init(name), null, errorAccess);
766754
throw ComponentUtil.notFunction(this, KeyImpl.init(name), member.getValue(), errorAccess);
@@ -990,21 +978,21 @@ private Collection.Key[] keysPreservingOrder(int access) {
990978
if (_udfs.isEmpty() && _data.isEmpty()) {
991979
return new Collection.Key[0];
992980
}
993-
981+
994982
List<Key> orderedKeys = new ArrayList<Key>(_udfs.size() + _data.size());
995-
996-
for (Entry<Key, UDF> entry: _udfs.entrySet()) {
983+
984+
for (Entry<Key, UDF> entry : _udfs.entrySet()) {
997985
if (entry.getValue().getAccess() <= access) {
998986
orderedKeys.add(entry.getKey());
999987
}
1000988
}
1001-
for (Entry<Key, Member> entry: _data.entrySet()) {
989+
for (Entry<Key, Member> entry : _data.entrySet()) {
1002990
Member member = entry.getValue();
1003991
if (member.getAccess() <= access && !(member instanceof UDF)) {
1004992
orderedKeys.add(entry.getKey());
1005993
}
1006994
}
1007-
995+
1008996
return orderedKeys.toArray(new Collection.Key[orderedKeys.size()]);
1009997
}
1010998

@@ -1194,7 +1182,8 @@ public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties
11941182
try {
11951183
return DumpUtil.toDumpData(_call(pageContext, KeyConstants.__toDumpData, udf, null, new Object[0]), pageContext, maxlevel, dp);
11961184
}
1197-
catch (PageException e) {}
1185+
catch (PageException e) {
1186+
}
11981187
}
11991188
}
12001189
}
@@ -1392,8 +1381,8 @@ public PageSource _getPageSource() {
13921381
return pageSource;
13931382
}
13941383

1395-
public ComponentPageImpl _getComponentPageImpl(PageContext pc) throws PageException {
1396-
return cpRef.get(pc);
1384+
public ComponentPageImpl _getComponentPageImpl() {
1385+
return cp;
13971386
}
13981387

13991388
public ImportDefintion[] _getImportDefintions() {
@@ -1728,7 +1717,7 @@ protected static Struct getMetaData(int access, PageContext pc, ComponentImpl co
17281717
if (!StringUtil.isEmpty(displayname)) sct.set(KeyConstants._displayname, displayname);
17291718

17301719
sct.set(KeyConstants._persistent, comp.properties.persistent);
1731-
// sct.set(KeyConstants._hashCode, comp.hashCode());
1720+
sct.set(KeyConstants._hashCode, comp.hashCode());
17321721
sct.set(KeyConstants._accessors, comp.properties.accessors);
17331722
sct.set(KeyConstants._synchronized, comp.properties._synchronized);
17341723
sct.set(KeyConstants._inline, comp.properties.inline);
@@ -1988,14 +1977,9 @@ private Object _set(PageContext pc, Collection.Key key, Object value, int access
19881977
"enable [trigger data member] in administrator to also invoke getters and setters");
19891978
if (existing != null) {
19901979
if (existing.getModifier() == Member.MODIFIER_FINAL) {
1991-
ComponentPageImpl tmp = cpRef.get(pc, null);
1992-
String componentName = tmp != null ? tmp.getComponentName() : "";
1993-
1994-
tmp = base.cpRef.get(pc, null);
1995-
String baseComponentName = tmp != null ? tmp.getComponentName() : "";
1996-
1997-
throw new ExpressionException("Attempt to modify a 'final' member [" + key + "] within the 'this' scope of the component [" + componentName
1998-
+ "]. This member is declared as 'final' in the base component [" + baseComponentName + "] or a component extended by it, and cannot be overridden.");
1980+
throw new ExpressionException("Attempt to modify a 'final' member [" + key + "] within the 'this' scope of the component [" + cp.getComponentName()
1981+
+ "]. This member is declared as 'final' in the base component [" + base.cp.getComponentName()
1982+
+ "] or a component extended by it, and cannot be overridden.");
19991983
}
20001984

20011985
}
@@ -2404,16 +2388,65 @@ public boolean isAccessors() {
24042388

24052389
@Override
24062390
public void setProperty(Property property) throws PageException {
2407-
top.properties.properties.put(StringUtil.toLowerCase(property.getName()), property);
2408-
// FUTURE getDefaultAsObject was added in Beta pahse of Lucee 7, so we keep the checkcast in place
2409-
if (((PropertyImpl) property).getDefaultAsObject() != null) scope.setEL(KeyImpl.init(property.getName()), ((PropertyImpl) property).getDefaultAsObject());
2410-
if (top.properties.persistent || top.properties.accessors) {
2411-
PropertyFactory.createPropertyUDFs(this, property);
2391+
// LDEV-3335: Handle property inheritance and overrides
2392+
PropertyImpl propImpl = (PropertyImpl) property;
2393+
PageSource propOwnerPS = propImpl.getOwnerPageSource();
2394+
2395+
// Check if this property is overriding an existing property (same name already registered)
2396+
String propNameLower = StringUtil.toLowerCase(propImpl.getName());
2397+
PropertyImpl existing = (PropertyImpl) top.properties.properties.get(propNameLower);
2398+
boolean isOverride = existing != null && propOwnerPS == null;
2399+
2400+
boolean isInherited = propOwnerPS != null && !propOwnerPS.equals(getPageSource());
2401+
2402+
if (isInherited && !isOverride) {
2403+
// Property is from a parent component - duplicate it to avoid sharing/mutation
2404+
propImpl = (PropertyImpl) propImpl.duplicate(false);
2405+
}
2406+
else if (propOwnerPS == null) {
2407+
// LDEV-3335: Property doesn't have owner set yet - set it to this component
2408+
// This happens for properties from __staticProperties that haven't been initialized
2409+
propImpl.setOwnerName(getAbsName(), getPageSource());
2410+
}
2411+
2412+
top.properties.properties.put(propNameLower, propImpl);
2413+
if (propImpl.getDefaultAsObject() != null) {
2414+
scope.setEL(propImpl.getNameAsKey(), propImpl.getDefaultAsObject());
2415+
}
2416+
// Create accessor UDFs if:
2417+
// 1. Component has accessors enabled, OR
2418+
// 2. Component is persistent, OR
2419+
// 3. Property is inherited and has accessors (need to create new UDFs with duplicated property)
2420+
// 4. Property is an override with accessors (child re-declaring parent property)
2421+
if (top.properties.persistent || top.properties.accessors || (isInherited && (propImpl.getGetter() || propImpl.getSetter()))
2422+
|| (isOverride && (propImpl.getGetter() || propImpl.getSetter()))) {
2423+
PropertyFactory.createPropertyUDFs(this, propImpl);
24122424
}
24132425
}
24142426

24152427
private void initProperties() throws PageException {
24162428
top.properties.properties = new LinkedHashMap<String, Property>();
2429+
// Call generated stub to initialize properties from static registry (zero overhead!)
2430+
if (top.cp != null) {
2431+
top.cp.initPropertiesStub(this);
2432+
}
2433+
2434+
// LDEV-3335: Add static flyweight accessor UDFs to _data and scope
2435+
Map<Key, UDF> staticAccessorUDFs = top.cp != null ? top.cp.getStaticAccessorUDFs() : null;
2436+
if (staticAccessorUDFs != null && !staticAccessorUDFs.isEmpty()) {
2437+
Iterator<Map.Entry<Key, UDF>> it = staticAccessorUDFs.entrySet().iterator();
2438+
while (it.hasNext()) {
2439+
Map.Entry<Key, UDF> entry = it.next();
2440+
Key key = entry.getKey();
2441+
UDF udf = entry.getValue();
2442+
2443+
// Only add if not manually overridden
2444+
if (!_data.containsKey(key)) {
2445+
_data.put(key, udf);
2446+
scope.put(key, udf);
2447+
}
2448+
}
2449+
}
24172450

24182451
// MappedSuperClass
24192452
if (isPersistent() && !isBasePeristent() && top.base != null && top.base.properties.properties != null && top.base.properties.meta != null) {
@@ -2424,8 +2457,11 @@ private void initProperties() throws PageException {
24242457
while (it.hasNext()) {
24252458
p = it.next().getValue();
24262459
if (p.isPeristent()) {
2427-
2428-
setProperty(p);
2460+
// LDEV-87: Don't override properties that child component has already declared
2461+
String propNameLower = StringUtil.toLowerCase(p.getName());
2462+
if (!top.properties.properties.containsKey(propNameLower)) {
2463+
setProperty(p);
2464+
}
24292465
}
24302466
}
24312467
}

core/src/main/java/lucee/runtime/ComponentPageImpl.java

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import java.util.Arrays;
2727
import java.util.Iterator;
2828
import java.util.List;
29+
import java.util.Map;
2930
import java.util.Map.Entry;
3031

3132
import jakarta.servlet.http.HttpServletRequest;
@@ -103,6 +104,11 @@ public abstract class ComponentPageImpl extends ComponentPage {
103104

104105
public static final lucee.runtime.type.Collection.Key REMOTE_PERSISTENT_ID = KeyConstants._Id16hohohh;
105106

107+
// Note: Static property registry is now generated per-class in bytecode, not in base class
108+
// Each generated component class has its own __staticProperties field and __getStaticProperties()
109+
// method
110+
// See PageImpl.writeOutStatic() for bytecode generation
111+
106112
private long lastCheck = -1;
107113

108114
private StaticScope staticScope;
@@ -598,8 +604,7 @@ private void _callRest(PageContext pc, Component component, UDF udf, String path
598604
pc.forceWrite(content);
599605
hasContent = true;
600606
}
601-
catch (IOException e) {
602-
}
607+
catch (IOException e) {}
603608
}
604609
}
605610

@@ -795,8 +800,7 @@ else if (args instanceof String) {
795800
try {
796801
args = new CFMLExpressionInterpreter().interpret(pc, str);
797802
}
798-
catch (PageException _pe) {
799-
}
803+
catch (PageException _pe) {}
800804
}
801805
}
802806
}
@@ -1148,6 +1152,40 @@ public StaticStruct getStaticStruct() {
11481152
return new StaticStruct();
11491153
}
11501154

1155+
/**
1156+
* Returns the static properties map for this component class. Components with properties will
1157+
* override this method to return their static property registry. Default implementation returns
1158+
* null for components without properties.
1159+
*
1160+
* @return Map of property names to PropertyImpl instances, or null if no properties
1161+
*/
1162+
public Map<String, lucee.runtime.component.PropertyImpl> getStaticProperties() {
1163+
return null;
1164+
}
1165+
1166+
/**
1167+
* LDEV-3335: Returns the static flyweight accessor UDF map for this component class. Components
1168+
* with accessors will override this to return their static UDF registry. Default implementation
1169+
* returns null for components without accessor UDFs.
1170+
*
1171+
* @return Map of accessor names to UDF instances, or null if no accessor UDFs
1172+
*/
1173+
public Map<Key, UDF> getStaticAccessorUDFs() {
1174+
return null;
1175+
}
1176+
1177+
/**
1178+
* Initializes component properties from the static property registry. Components with properties
1179+
* will override this method to provide optimized property initialization. Default implementation
1180+
* does nothing (no-op for components without properties).
1181+
*
1182+
* @param impl The ComponentImpl instance to initialize properties for
1183+
* @throws PageException if property initialization fails
1184+
*/
1185+
public void initPropertiesStub(ComponentImpl impl) throws PageException {
1186+
// No-op for components without properties
1187+
}
1188+
11511189
public abstract void initComponent(PageContext pc, ComponentImpl c, boolean executeDefaultConstructor) throws PageException;
11521190

11531191
public void ckecked() {

0 commit comments

Comments
 (0)