diff --git a/core/src/main/cfml/context/admin/language.xml b/core/src/main/cfml/context/admin/language.xml
deleted file mode 100644
index d3e0dda438..0000000000
--- a/core/src/main/cfml/context/admin/language.xml
+++ /dev/null
@@ -1,1481 +0,0 @@
-
-
-
-
- Request timeout via URL
-
- Angabe des Parameters [RequestTimeout] in der URL berücksichtigen (Verhalten wie CFML 5, 7 & 8)
- Application Listener
- Legt fest, wie Request verarbeitet und welche Templates einbezogen werden sollen.
- Mode
- Aktuell
-
- Aktuell bis Root (CFML Default)
- Root (Wurzelverzeichnis)
- Definiert wo nach den Dateien 'Application.cfc/application.cfm' gesucht werden soll. Beim Typ 'none' ist diese Einstellung ohne Bedeutung.
- Sucht nur im aktuellen Verzeichnis nach der Datei 'Application.cfc/Application.cfm'.
- Sucht nach der Datei 'Application.cfc/Application.cfm' vom aktuellen Verzeichnis aus zurück bis zum Webroot Verzeichnis.
- Sucht nur im Webroot Verzeichnis nach der Datei 'Application.cfc/Application.cfm'.
-
- Type
- Klassisch (CFML < 7)
- Gemischt (CFML >= 7)
- Modern
- Kein
-
- Wählen Sie welche Art von Listener verwendet werden soll
- Klassisches Handling. Lucee sucht nur nach der Datei 'Application.cfm' und der entsprechenden Datei 'onRequestEnd.cfm'
- Gemischtes Handling. Lucee sucht sowohl nach der Datei 'Application.cfm/onRequestEnd.cfm' wie auch nach der Datei 'Application.cfc'
- Modernes Handling. Lucee sucht nur nach der Datei 'Application.cfc'
- Bei einem Request wird ausschliesslich die entsprechende Datei aufgerufen
- Bitte geben Sie einen Wert für das Script-Protect ein
-
- Request Timeout
- Legt die Zeit fest, wie lange Lucee auf die Beendigung eines Requests warten soll. Das heisst, dass die Ausführung des Requests beim Überschreiten dieser Zeit abgebrochen wird. Diese Verhaltensweise kann von dem Tag CFSetting übersteuert werden.
- Script-Protect
- Script-Protect überprüft alle Scopes ob die Daten von ausserhalb kommen (cgi, cookie, form, url)
- Definieren Sie individuell welche Scopes geprüft werden sollen und welche nicht
- Durch die Konfiguration von Script-Protect schützen Sie ihr System vor 'Cross-Site Scripting'
-
- Script-Protect ist nicht aktiv
- Definert Applikationseinstellungen, die als Standardwert für alle Webs gelten.
- Hier können Sie verschiedene Standardeinstellungen für den Applikations Kontext erfassen. Diese Einstellungen können von dem Tag CFApplication oder der Application.cfc übersteuert werden.
- dem Mapping zuweisen
- abbrechen
- ändern
-
- kompilieren
- neu
- löschen
- downloaden
- ausführen
- filter
-
- installieren
- OK
- optimieren
- leeren
- reparieren
- zurücksetzen
-
- speichern
- suchen
- einstellung
- senden
- deinstallieren
- aktualisieren
-
- überprüfen
- Java CFX Tags
- Klasse
- Bitte geben Sie einen Wert für die Klasse an. (Zeile
- Name
- Kein Zugriff auf die CFX Funktionalität
-
- Bitte geben Sie einen Wert für das Ressource Charset ein
- Bitte geben Sie einen Wert für das Template Charset ein
- Bitte geben Sie einen Wert für das Web Charset ein
- Ressourcen Charset
- Charset das verwendet wird um die diversen Ressourcen (Files, Zip, Ftp usw.) einzulesen oder zu beschreiben
- Hier definieren Sie das Charset (Zeichensatz) das für verschiedene Einsatzwecke verwendet werden soll
-
- Template Charset
- Charset das verwendet wird um die verschiedenen Templates (.cfm und .cfc Files) einzulesen
- Hier definieren Sie das Charset (Zeichensatz) das für verschiedene Einsatzwecke verwendet werden soll
- Web Charset
- Charset das als standardmässiger charset des Output Streams, zum Einlesen von form, url und cgi Scope und zum Schreiben und Lesen des Headers verwendet wird
- Basis/Root Komponente
-
- Jede Komponente die nicht explizit eine andere Komponente erbt (Attribut 'extends') erbt diese Komponente, d.h. das jede Komponente diese Komponente direkt oder indirekt erbt.
- Bitte geben Sie einen Wert für die Basis/Root Komponente ein.
- Komponente
- Komponetenausgabe Template (dump)
- Wenn Sie ein Komponente direkt über den Browser aufrufen, wird dieses Template für die Darstellung verwendet. (Beispiel: https://www.lucee.org/ch/lucee/common/Example.cfc)
- Bitte geben Sie einen Eintrag für das 'dump' Template an.
-
- Zugriffsbeschränkung für Daten Mitglieder einer CFC
- Definiert wie die Variablen des 'this' Scopes (Data Members) ausserhalb einer CFC angesprochen werden können. Eine strenge Objektorientierung würde verlangen, dass ein solcher Zugriff von Aussen gar nicht erst möglich wäre (access=private).
- package
- private
- public (CFML Standard)
- remote
-
- Definert Komponenteneinstellungen, die als Standartwert für alle Webs gelten.
- Magic functions
- Wenn eine Eigenschaft einer Komponente fehlt (oder geschützt ist), prüft Lucee weiter ob ein passender "getter" oder "setter" verfügbar ist.
- Beispiel: "myComponent.properyName", wenn die Komponente 'myComponent' keine zugreifbare Eigenschaft mit dem Namen 'propertyName' hat,
- sucht Lucee nach einer entsprechenden CFC-Funktion (Methode) mit dem Namen "getPropertyName". Für Schreiboperationen auf eine solche Eigenschaft wird nach einer Methode "setPropertyName" in der Komponente gesucht.
-
- Allow Variable Scope
- Definiert, ob eine Komponente einen eigenständigen "Variables" Scope parallel zum "this" Scope hat (CFML Standard) oder nicht. Wenn nicht, dann werden alle nicht spezifizierten Variablen in den "this" scope geschrieben.
- Definiert wie Komopenten von Lucee verarbeitet werden.
-
- Archiv
- Bitte geben Sie einen Wert für den Archivnamen an. (Zeile
- Untergeordnete Verzeichnisse einbeziehen
- Untergeordnete Verzeichnisse nach Customtags durchsuchen (für Archive nicht unterstützt)
- Lokales Verzeichnis einbeziehen
- Lokales Verzeichnisse aus welchen der Customtag aufgerufen wird, nach dem Customtag durchsuchen
-
- Resourcen
- Einstellungen
- Ressource
- Bitte geben Sie einen Wert für die Ressource an. (Zeile
- Primär
- Trusted
-
- Debugging Template
- Dieses Template wird für die Ausgabe der Debuginformationen
- Bitte geben Sie einen Wert für das Debugging Template an.
- Debug Informationen anzeigen
- Falls eingeschaltet, erstellt Lucee eine Debuggingausgabe für den aktuellen Request
- Memoryverbrauch loggen.
-
- Definiert ob der Memoryverbrauch des Systems geloggt werden soll oder nicht
- Memory Logger
- Datei in welchem der Memoryverbrauch geloggt wird
- Bitte geben Sie einen Wert für die Zeitzone an.
- Typ
- Beschreibung
-
- Lediglich die Anzahl der Argumente ist auf {max} beschränkt.
- Sie muss jedoch mindestens {min} Argument(e) haben.
- Sie muss mindestens {min} Argument(e) haben jedoch maximal {max}.
- Name
- Required
- Für diese Funktion gibt es keine Beschränkung hinsichtlich der Argumente, die verwendet werden dürfen.
-
- Die Argumente für diese Funktion sind fest vorgegeben. Ausser den nachfolgenden Argumenten dürfen keine weiteren verwendet werden.
- Diese Funktion hat keine Argumente
- Argumente
- Typ
- Beschreibung
- Lediglich die Anzahl der Attribute ist auf {max} beschränkt.
-
- Es muss mindestens {min} Attribut(e) haben.
- Es muss mindestens {min} Attribut(e), jedoch maximal {max.} haben
- Name
- Required
- Für dieses Tag gibt es keine Beschränkung was für Attribute verwendet werden dürfen.
- Die Attribute für dieses Tag sind fest vorgegeben. Ausser den nachfolgend angegebenen Attributen dürfen keine weiteren verwendet werden.
-
- Dieses Tag hat eine feste Definition von Attributen (siehe nachfolgend), darüber hinaus erlaubt das Tag jedoch weitere frei definierbare Attribute zu verwenden.
- Dieses Tag erlaubt einzig ein Attribut Wert (keinen Namen).
- Dieses Tag hat keine Attribute
- Attribute, die durch für das Tag unterstützt sind.
- Attribute
- Dieses Tag darf einen Body haben, muss aber nicht.
-
- Dieses Tag darf keinen Body haben.
- Dieses Tag muss einen Body haben.
- Body
- Geben Sie ein individuelles Error-Template an.
- Status Code
- Soll im Fehlerfall ein abweichender Statuscode zurückgegeben werden oder soll 200 beibehalten werden
-
- Missing Template Error (404)
- General Error Template (500)
- Template das beim fehlen eines template verwendet wird. Diese Einstellung kann über den Tag CFError übersteuert werden.
- Template das in einem Fehlerfall verwendet werden soll. Diese Einstellung kann über den Tag CFError übersteuert werden.
- Tag
- Tage
-
- Stunde
- Der Wert des Feldes Stunde muss einen positiven Wert enthalten (Wert > 0)
- Stunden
- Minute
- Der Wert des Feldes Minute muss einen positiven Wert enthalten (Wert > 0)
-
- Minuten
- Monat
- Nein
- Sekunde
- Der Wert des Feldes Sekunde muss einen positiven Wert enthalten (Wert > 0)
-
- Sekunden
- Jahr
- Ja
- german (standard)
- Passwort ändern
- Passwort für diesen Administrator ändern.
-
- Standard Passwort setzen
- Legen Sie das Standard Passwort für alle Web Administratoren fest.
- Neues Passwort
- Das neue Passwort für den Administrator.
- Bitte geben Sie einen Wert für das neue Passwort an
- Das neue Passwort ist zu kurz. Die länge des Passworts muss mindestens 6 Zeichen betragen.
-
- Altes Password
- Das alte, zu ändernde Passwort.
- Bitte geben Sie einen Wert für das alte Passwort an
- Das alte Passwort ist zu kurz. Die länge des Passworts muss mindestens 6 Zeichen betragen.
- Passwort
- Bitte geben Sie ein Passwort ein
-
- Passwort zurücksetzen
- Passwort für das gewählt Web zurücksetzen
- Geben Sie das neue Passwort erneut ein
- Bitte geben Sie das neue Passwort erneut ein
- Geben Sie das Passwort erneut ein
- Bitte geben Sie das Passwort nochmals ein
-
- Das neue Passwort und dessen Wiederholung sind nicht identisch.
- Web
- Standard Encoding
-
- Log Level
- Log Datei
-
- Bitte geben Sie einen Wert für die Log Datei an.
- Mail Server
- Sie können mehrere Mailsserver definieren. Wenn Sie eine Mail absenden, versucht Lucee die Mail der Reihe nach über einen der angegebenen Mailserver zu versenden.
- Bitte geben Sie einen Wert für das Standard Encoding ein
- Passwort
- Bitte geben Sie einen Wert für das entsprechende Passwort an. (Zeile
-
- Port
- Bitte geben Sie einen Wert für den Port (Zeile
- ) vom Typ Nummer an.
- Server (SMTP)
- Bitte geben Sie einen Wert für den Mailserver an. (Zeile
- Mail Einstellungen
-
- Spooler an
- Spool Intervall
- Timeout
- Benutzername
- Bitte geben Sie einen Wert für den Benutzernamen an. (Zeile
- Archiv
-
- Erstellen Sie aus einem Mapping ein Lucee Archive (ra)
- Archiv
- Name der Archivdatei (ra oder ras) (Absolut oder relativ zum Webroot).
- Bitte geben Sie einen Wert für den Archivnamen an. (Zeile
- Sicher
- Source Dateien aus dem Archiv ausschliessen. Die Source Dateien werden nur für die Ausgabe von Codeprints bei Fehlern verwendet.
-
- Archiv erstellen
- Kompilieren Sie alle cfm und cfc-Dateien innerhalb des Mappings
- Bei Fehler stoppen
- Legt fest, ob bei einem Fehler die weitere Kompilierung gestoppt werden soll
- kompilieren
- Hier können Sie ein einzelnes Mapping bearbeiten oder aus einem bestehenden Mapping ein Lucee Archiv erstellen.
-
- Bitte beachten Sie, dass nur Seiten, die von Lucee verarbeitet werden diese Mappings kennen (cfm, cfml, cfc). Wenn Sie auch Dateien, die nicht von Lucee verarbeitet werden verwenden möchten, müssen Sie virtuelle Mappings auf Ihrem Applikationsserver erstellen.
- Ressource
- Ressource
- Pfad der zu mappenden Ressource (Absolut oder relativ zum Webroot).
- Bitte geben Sie einen Wert für die Ressource an. (Zeile
- Primär
-
- Legt fest, wo cfm-Dateien vorrangig gesucht werden.
-
- Top Level
- Trusted
-
- Virtuell
- Fehlerreport
-
- bugs@lucee.ch
- Kompatibel zu ColdFusion® Version
- Kontakt
- Info
- Anzahl Kontexte
- Lucee Datum/Zeit
-
- Feature Anfragen
- features@lucee.ch
- Info
- info@lucee.ch
- Installierte Funktions<br>Bibliotheken
-
- Installierte Tag<br>Bibliotheken
- Der Server Administrator ermöglicht Ihnen Updates und Patches für Ihre Lucee Edition vorzunehmen und die Engine per Mauklick neu zu starten. Zusätzlich können Sie in der Develop und Enterprise Edition die einzelnen Webkontexte vorkonfigurieren und diverse Beschränkungen und Konfigurationen individuell pro Webkontext einrichten.
- Lucee, die CFML engine. Schnell, preiswert und einfach zu bedienen. Mit Lucee haben sie sich für den performanten und qualitativ hochwertigen Weg von CFML entschieden. Passen Sie Ihren Webkontext nach Ihren Bedürfnissen und Wünschen an. Dafür steht Ihnen hier der Web Administrator zur Verfügung.
- Erhältliche Editionen
- Community
-
- Lucee Community ist für den einfachen Einsatz gedacht. Bis auf wenige Einschränkungen bietet die Community Version den vollen Sprachumfang von Lucee und dies völlig umsonst.
- Lucee ist in vier verschiedenen Editionen verfügbar, zugeschnitten für die verschiedenen Einsatzgebiete und Bugets.
- Develop
- Die Develop Version ist eine Version, welche die Entwickler addressiert, also gedacht ist um damit CFML Applikation zu erstellen. Diese Version darf jedoch nicht produktiv eingesetzt werden.
- mehr
- Enterprise
-
- Die Enterprise Version von Lucee ist die grösste und umfassenste Version, gedacht um in einem grösseren Umfeld einzusetzen.
- Professional
- Die Professional Version bietet den vollen Sprachumfang von Lucee, es muss also auf keine Feature verzichtet werden. Mit der Professional Version können mehrere Webs auf einem Server betrieben werden, die Anzahl Webs wird jedoch durch den Lizenspreis eingeschränkt.
- Betriebssystem
- Hol Dir Deine Lucee Lizenz
- Release Datum
-
- Verkauf
- sales@lucee.ch
- Seriennummer
- Seriennummer für Lucee
- Server Datum/Zeit (mm/dd/yyyy HH:mm:ss):
- verwendet
-
- Version
- Proxy nicht verwenden
- Proxy verwenden
- Proxy verwenden
- URL eines Proxy Server im Stil 'http://myproxyserver.org/'
- Bitte geben Sie einen Wert für den Proxy Port an
-
- Passwort
- Passwort für den Proxy
- Port
- Server
- Port für den Proxy Server (Vorgabe:80)
- Definieren Sie einen globalen Proxy, der standardmäßig in mehreren Tags verwendet wird (cfhttp, cfftp, cfmail ...)
- URL eines Proxy Server im Stil 'http://myproxyserver.org/'
-
- Proxy Einstellungen
- Benutzername
- Benutzername für den Proxy
- Definieren Sie einen Proxy, welcher an diversen Stellen (cfhttp, cfftp, cfmail ...) in Lucee Verwendung findet
- Standard Encoding
-
-
- Locale
- Definiert die Standard-'Locale', die innerhalb einer Web-Instanz verwendet werden soll.
- Please enter a value for the default encoding
- --- andere ---
- Hier können Sie regionale Einstellungen vornehmen, die Vorgabe für alle Web-Instanzen sind. Auf die aktuelle Instanz haben diese Werte keinen Einfluss.
- Server Einstellung
-
- Time server (NTP)
- Time server der die aktuelle Zeit zürück gibt. Falls gesetzt, wird in Lucee diese Zeit anstelle der lokalen Server-Zeit verwendet (Beispiel: swisstime.ethz.ch, time.nist.gov).
- Bitte wählen Sie einen Wert für die Zeitzone aus.
- Zeitzone
- Definiert die gewünschte Zeitzone für Lucee. Diese Einstellung ändert die Zeit für den Kontext der Webs.<br>
- Lucee lässt Sie Ihre eigenen individuellen Locale-, Zeitzonen- und Zeitservereinstellungen vorzunehmen.
-
- Admin Access
- Definiert den Zugang zum Remote Client, dessen Password und Security Key, die Security key kann innerhalb des Remote Client bezogen werden
- Passwort für den remote Server Administrator
- Passwort für den Remote Web Administrator
- Passwort für den Zugriff auf den Remote Lucee Server Administrator
- Passwort für den Zugriff auf den Remote Lucee Web Administrator
-
- Verbindung
- Verbindung zum Remote Client, komplette URL (inkl. Port) und HTTP Access
- Definiert Clients, mit welchen die Einstellungen dieses Administrators, synchronisiert werden sollen
- Remote Client erstellen
-
- Remote Client updaten
-
-
- Bei "<Buttons.downloadArchive>" wird der Download des Archivs auf dem Remote Client ignoriert, das Archiv wird jedoch angelegt. In diesem Fall empfiehlt es sich den Remote Client nicht einzubeziehen.
- Bezeichnung
- Die Bezeichnung für den Remote Client fehlt
- Liste der Clients
-
- Neuen Remote Client erstellen
- Aktion
- Es wurde bereits <tries> mal versucht diesen Task auszuführen. <triesleft> Versuche stehen noch aus
- Dieser Task konnte trotz <tries> Versuchen nicht korrekt ausgeführt werden
-
- Fehlermeldungen
- Ausführungszeit
- 1-100 von <recordcount> offenen Tasks
- Letzte Ausführung
- Name
-
- Next execution
- Nächste Ausführung in Minuten
- Zur Zeit gibt es keine offenen Tasks
- Liste der fehlgeschlagenen Tasks. Die hier grün aufgelisteten werden nochmals ausgeführt. Die rot gelisteten Tasks konnten nicht ausgeführt werden.
- Status
- Anzahl Versuche
-
- Anzahl verbleibender Versuche
- Typ
- URL
- Das Administrator Passwort für den Remote Client fehlt
- Proxy Settings
- Proxy Settings welche für die Verbindung verwendet werden sollen
-
- Passwort
- Port
- Proxy Server Port
- Server
- Proxy Server (Host)
- Username
-
- Sicherheitsschlüssel
- Geben Sie hier den Schlüssel des Remote Clients an. Sie finden ihn unter Remote-Scherheitsschlüssel im Administrator des Remote Clients
- Der Sicherheitsschlüssel für den Remote Client fehlt
- Falls dieser Web Administrator von einem anderen Server aus synchronisiert werden soll, müssen sie den unten angegebenen Schlüssel bei der Definition der Remote Client Verbindung angeben.
- Passwort
- Http Access Auhtentication Passwort
-
- Username
- Http Access Auhtentication Username
- Definieren sie, mit welchen Clients die hier gemachten Einstellungen synchronisiert werden sollen
- Remote Client Synchronisation
- URL
- Die Remote Client URL fehlt
-
- Pfad
- Pfad zur Admin.cfc (Beispiel: /lucee/admin.cfc?wsdl)
- Der Pfad zur Admin.cfc fehlt
- Server
- Remote Client Server (Beispiel: http://lucee.ch)
- Remote Client Server
-
- Cluster Scope
- Definiert für was alles der Remote Client verwendet werden soll
- Admin Synchronisation
- Verwendung
- Scheduled Task erstellen
- Aktuelle Datum/Zeit dieses Lucee Kontexts: (mm/dd/yyyy hh:mm tt)
-
- täglich
- Hier können Sie Scheduled Tasks hinzufügen, bearbeiten oder löschen.
- Definierte Scheduled Tasks
- Die rot gekennzeichneten Tasks sind abgelaufen und starten nicht mehr.
- Enddatum
- Endet am
-
- Endzeit
- Alle
- Ausführen
- Ausführung Datum/Zeit
- Ausführungszeit
- Datei
-
- Datei in der die Ausgabe gespeichert werden soll.
- Intervall
- Intervall in dem der Task ausgeführt wird.
- Intervall Typ
- Ausführungsintervall des neuen Tasks
- monatlich
-
- Name
- URL, die vom Task ausgeführt werden soll.
- Name des neuen Tasks (dieser Name muss eindeutig sein).
- Bitte geben Sie einen Wert für den Namen des Tasks an.
- einmalig
- Ausgabe
-
- Passwort
- Passwort, um auf die geschützte URL zuzugreifen.
- Port
- Port der aufzurufenden URL (HTTP Standard: 80)
- Proxy Einstellungen
- Passwort, um auf den geschützten Proxy zuzugreifen.
-
- Port des Proxys
- Username, um auf den geschützten Proxy zuzugreifen.
- Speichern
- URL auflösen
- Wandelt relative URLs in absolute um
- Server
-
- Startdatum
- Begint am
- Startzeit
- Legt fest, ob die Ausgabe in einer Datei gespeichert werden soll oder nicht.
- Timeout
- Timeout in Sekunden. Definiert wie lange der Task auf eine Antwort von der aufgerufenen URL warten soll.
-
- URL
- URL des neuen Tasks.
- Bitte geben Sie einen Wert für die URL des Tasks an.
- Username
- Username, um auf die geschützte URL zuzugreifen.
- wöchentlich
-
- Application Timeout
- Legt die Zeit fest, wie lange Lucee für inaktive Applikationen den Application-Scope erhält. Diese Verhaltensweise kann von dem Tag CFApplication übersteuert werden.
- Resultsets durchsuchen
- Wenn eine Variable keinen vorangestellten Scope hat (Beispiel: #myVar# anstelle von #variables.myVar#), kann Lucee (nach dem CFML Standard) auch verfügbare Query-Resultsets durchsuchen.
- Cascading
- Abhängig von dieser Einstellung durchsucht Lucee gewisse Scopes, um eine im CFML-Code aufgerufene Variable zu finden. Dieses passiert jedoch nur, wenn die Variable ohne vorangestellten Scope aufgerufen wird. (Beispiel: #myVar# anstelle von #variables.myVar#)<br>- strict: durchsucht nur den Variables Scope<br>- small: durchsucht die Scopes: Variables, Cgi, Url und Form<br>- standard (CFML Standard): durchsucht die Scopes: Variables, Cgi, Url, Form und Cookie
-
- Client Cookies
- Client Cookies ein oder ausschalten. Diese Verhaltensweise kann von dem Tag CFApplication übersteuert werden.
- Client Management
- Standardmässig kann Client Management eingeschaltet werden. Diese Verhaltensweise kann von dem Tag CFApplication übersteuert werden.
- Domain Cookies
- Domain Cookies ein oder ausschalten. Diese Verhaltensweise kann von dem Tag CFApplication übersteuert werden.
-
- Local Scope Modus
- Always
- Definiert wie der Lokal Scope innerhalb einer UDF von einer Variable ohne Scope angesprochen wird.<br>
- - always: der Lokal Scope wird immer verwendet<br>
- - update (CFML Standard): der Lokal Scope wird nur verwendet, wenn der entsprechende Key darin bereits existiert.
- Update (CFML Standard)
-
- Url und Form kombinieren
- Mit dieser Einstellung kann festgelegt werden, ob Lucee den Url und Form Scope zu einem einzigen Scope zusammenfasst oder nicht. Beim CFML Standard findet diese Zusammenfassung nicht statt.
- Definert Scopeeneinstellungen, die als Standardwert für alle Webs gelten sollen.
- Session Management
- Standardmässig kann Session Management eingeschaltet werden. Diese Verhaltensweise kann von dem Tag CFApplication übersteuert werden.
- Session Timeout
-
- Legt die Zeit fest, wie lange Lucee für inaktive Sessions den Session-Scope erhält. Diese Verhaltensweise kann von dem Tag CFApplication übersteuert werden.
- Session Typ
- Application
- JEE
- JEE Sessions erlauben es Lucee Sessions über einen JEE Server-Cluster zu verteilen. Wenn Sie diese Einstellung ändern verlieren Sie die aktuelle Session und müssen sich erneut einloggen.
- small
-
- standard (CFML Default)
- strict
- Der Wert Tage für
- den Timeout muss ein ganzzahlige Wert sein.
- Der Wert Stunden für
- Der Wert Minuten für
-
- Der Wert Sekunden für
- Hier können Sie festlegen, wie Lucee Scopes abarbeitet.
- Collection
- Collections
- Collection erstellen
- Hier können Sie Search Collections verwalten, erstellen, indexieren und löschen. Standardmässig verwendet Lucee LUCENE als Suchengine.
-
- Verzeichnispfad
- Bitte geben Sie einen Wert für den zu indexierenden Pfad an.
- Extern
- Dateierweiterungen
- Bitte geben Sie einen Wert für Erweiterungen die indexiert werden sollen an.
- Unterverzeichnisse einschliessen
-
- Sprache
- Letzte Aktualisierung
- Mapped
- Bitte geben Sie einen Wert für den Namen der Collection an.
- Bitte geben Sie einen gültigen Wert für den Pfad der Collection an.
- Name
-
- Kein Resultat für Ihre Anfrage
- Online
- Pfad
- Hinzufügen/Aktualisieren des Pfadindex
- Resultate {startrow} - {endrow} von {recordcount} Resultaten gesucht in {recordssearched} Records
- Ergebnisse der Suche
-
- Suchbegriff eingeben
- Bitte geben Sie einen Suchbegriff ein.
- Collection durchsuchen
- URL
- Lesezugriff
- definiert den Lesezugriff
-
- Schreibzugriff
- definiert den Schreibzugriff
- CFML Umgebung
- Einstellungen die festlegen wie Lucee Code mit dem Hostsystem interagiert.
- CFX
- Die Einstellungen für die CFX Tags können geändert werden. Im 'Server Administrator' global definierte Tags können auch verwendet werden.
-
- CFX tags
- Mit Hilfe von CFX Tags können Java Klassen geladen werden, die ev. volles Zugriffsrecht auf das Hostsystem gewähren.
- Custom Tags
- Custom tags können 'Web Administrator' hinzugefügt, gelöscht und geändert werden.
- Datasource
- Definiert wieviele Datenquellen im 'Web Administrator' hinzugefügt, gelöscht und geändert werden können.
-
- unbeschränkt
- Debugging
- Die Einstellungen für Debugging können im 'Web Administrator' geändert werden.
- Definieren Sie die Zugriffsrechte für die verschiedenen Web Kontexte (webapps). Unter dem Reiter 'Allgemein' legen Sie die Standardrechte für alle Web Kontexte fest. Individuelle Einstellungen können Sie für jedes einzelne Web im Reiter 'Individuell' definieren.
- Dateizugriff
- all
-
- Legt fest, wie Lucee mit dem lokalen Dateisystem in einer Instanz interagieren kann.<br>- none: erlaubt keinen Zugriff auf das lokale Dateisystem<br>- local: erlaubt nur Dateizugriffe innerhalb des Webrootverzeichnisses<br>- all: erlaubt vollen Dateizugriff auf das Hostsystem.<br>
- local
- none
- Tags & Funktionen
-
- Tags and Funktionen, die ein potentielles Sicherheitsrisiko für das Hostsystem darstellen.
- Allgemeiner Zugriff
- Definiert den allgemeinen Zugriff auf den Administrator und das Tad cfadmin
- Direkter Java Zugriff
- Erlaubt den Zugriff auf Java Methoden und Eigenschaften aus Lucee Code (Beispiel: stringValue.substring(2,5)). Wenn Sie direkten Java Zugrif zulassen, kann dies ein potentielles Sicherheitsrisiko darstellen.
- Mail
-
- Die Maileinstellungen können im 'Web Administrator' geändert werden.
- Mappings
- Mappings können 'Web Administrator' hinzugefügt, gelöscht und geändert werden.
- Remote
- Es wird erlaubt das der User seine Einstellungen mit einem anderen lucee synchronisiern kann
- Scheduled Task
-
- Die Einstellungen für Scheduled Task können im 'Web Administrator' geändert werden.
- Suche
- Die Einstellungen für Suche können im 'Web Administrator' geändert werden.
- Einstellungen (Region, Komponenten, Scope)
- Die Einstellungen Region, Komponenten und Scope können im 'Web Administrator' geändert werden.
- Definieren Sie hier Sicherheitseinstellungen für einzelne Web Kontexte (webapps).
-
- Hostname
- Neuen Web Kontext erstellen
- Pfad
- Web Kontexte für die es bereits einen spezifische Einstellung gibt. Sie können diese Kontexte anpassen oder löschen.
- Spzifische Web Kontexte
- Web Kontext
-
- Allgemein
- Individuell
- Tag CFExecute
- Dieser Tag kann verwendet werden um Prozesse auf dem lokalen Hostsystem auszuführen.
- Tag CFImport
- Dieser Tag kann verwendet werden um JSP und Lucee Tag Bibliotheken zu importieren.
-
- Tag CFObject / <br>Funktion createObject
- Mit dem Tag CFObject und der Funktion createObject können Java Objekte geladen werden. Wenn Sie diese Option ausschalten, können Sie nur noch Objekte des Typs 'component' erstellen.
- Tag CFRegistry
- Mit dem Tag CFRegistry haben Sie vollen Zugriff auf die Registry des Hostsystems.
- Standard Zugriffsrechte
-
- Hier können Sie die Zugriffsrechte festlegen, die für alle Instanzen verwendet werden sollen. Falls zugelassen, können diese Einstellungen in den lokalen 'Web Administratoren' überschrieben werden.
- Web Administrator
- Hier können Sie die Zugriffsrechte für die Einstellungen festlegen, die in den 'Web Administratoren' überschrieben werden können.
-
- Sie können Lucee auf eine neue Version patchen, also bekannte Fehler ausbügeln
- und Optimierungen innerhalb ihrer Version einspielen.
- Update ausführen
- Spielen Sie die aktuellsten Pacthes für Ihre Version ein. Nach einem erfolgten Update, müssen Sie sich neu in den Administrator einloggen.
-
- Update ausführen
- Info
- URL
- Definieren Sie die URL von der ein Lucee Update bezogen werden kann, typischerweise 'https://www.lucee.org'
- Für Ihre Version {current} steht kein Patch zur Verfügung
- Updates entfernen
-
- Entfernen Sie alle nach der Grundinstallation nachträglich installierten Updates.
- Updates entfernen
- Lucee neu starten
- Hier können Sie Lucee neu starten. Nach erfolgtem Restart werden bestehende Sitzungen entfernt. Sie müssen sich in den Administrator erneut einloggen.
- Definieren Sie wie und wo Ihre Lucee Version ihre Patches bezieht. Damit die eine Änderung dieser Einstellung aktiv wird, ist ein Neustart von Lucee erforderlich.
- Einstellungen
-
- Typ
- Automatisch
- Manuell
- Definieren Sie hier wie Lucee gepatcht werden soll, 'Automatisch' steht dafür, dass Lucee automatisch, täglich nach updates sucht. 'Manuell' bedeutet, dass ein Update nur manuell ausgeführt werden kann.
- Für Ihre Version steht ein Patch zur Verfügung, Sie haben die Version {current} installiert, die aktuell verfügbare Version ist {available}
- Kontrolle der Ausgabe von Lucee
-
- Lucee Version ausgeben
- Lucee Version im Response Header zurückgeben
- Kontrolle der Ausgabe von Lucee
- Whitespace management
- Unterdrückt alle Whitespace (Leerzeichen, Tabs und Zeilenumbrüche), die in der Ausgabe einem Whitespace folgen
- Neue Datenquelle erstellen
-
- Datenquelle aktualisieren
- Neue Datenquelle erstellen
- Einstellungen
- Erlaubte Operationen
- Blob
- Erlaubt das einbeziehen von BLOBs
-
- Check
- Clob
- Erlaubt das einbeziehen von CLOBs
- Verbindungslimitierung (max)
- Beschränkt die Anzahl Verbindungen die zur Datenbank aufgebaut werden.
- - inf -
-
- Inaktivitäts Timeout (in Minuten)
- Definiert wie lange eine stehende unverwendete Verbindung aufrechterhalten wird, bevor Sie beendet wird.
-
- Verbindungs Timeout
- Definiert wie lange eine stehende Verbindung aufrechterhalten wird, bevor Sie beendet wird.
-
- Datenbank
- Name der Datenbank, welche verbunden werden soll.
- Host/Server
- Host Name wo die Datenbank liegt
-
- Passwort
- Passwort für den Zugriff auf die Datenbank
- Port
- Der Port der Datenbank die angesprochen werden soll.
- Benutzername
- Benutzername für den Zugriff auf die Datenbank
-
- Vorhandene Datenquellen
- Name
- Bitte geben Sie einen Namen für die Datenquelle ein.
- Single Quotes erhalten
- Erhält die einfachen Anführungszeichen (') in den SQL-Statements, die im Tag CFQuery definiert werden.
- Readonly Datenquellen
-
- Readonly Datenquellen werden im 'Server Administrator' für alle Web Instanzen erstellt und können im 'Web Administrator' nicht geändert werden.
- Typ
- Provider
- URL eines Provider der die benötigten Komponenten (FFMpeg Binaries) anbietet.
- Fehlende Provider Definition
- Die benötigten Video Komponenten sind auf Ihrem System installiert.
-
- Video Komponenten sind zwar installiert, jedoch können sie nicht korrekt ausgeführt werden:
- Wir empfehlen Ihnen eine manuelle Installation vorzunehmen.
- Da für das Tag cfvideo/cfvideoplayer betriebssystemspezifische Video Komponenten benötigt werden, sind diese nicht mit Lucee gebundelt. Dies würde den Umfang der Software unnötig vergrössern. Zudem dürfen gewisse enthaltene Codecs nicht vertrieben werden. Die Verwendung derer ist jedoch uneingeschränkt, weshalb sie diese nachladen können. Sie können diese Komponenten direkt vom Provider laden oder hier per Formular hochladen.
- Video Komponenten (ffmpeg.zip) werden direkt über Formular hochgeladen und in Lucee kopiert (keine Installation). Als Quelle dient z.B. {provider}
- Video Komponenten über Upload
- Video Komponenten werden direkt vom Remote Server geladen und in Lucee kopiert (keine Installation).
-
- Video Komponenten über URL
- Eine Manuelle Installation wird wie folgt vorgenommen: Navigieren Sie zur Adresse {provider} und laden sie dort die ffmpeg.zip für Ihr Betriebssystem ({OS-Name}) herunter. Kopieren Sie diese Datei (nicht entpacken) in das Verzeichnis {directory}. Falls Sie für Ihr Betriebssystem keinen Download finden, kontaktieren Sie uns.
- Manuelle Installation
- Upload
- Video Komponenten (ffmpeg.zip)
- Fehlende Upload Definition
-
- Video Komponenten sind auf Ihrem System installiert.
- Video Komponenten sind zwar installiert, jedoch können sie nicht korrekt ausgeführt werden. Wechseln Sie in den Lucee Server Administrator, um dies zu reparieren:
- Video Komponenten sind nicht auf Ihrem System installiert. Um diese zu installieren wechseln sie in den Lucee Server Administrator.
-
-
-
-
-
-
-
-
-
-
- Request timeout in URL
-
- When the URL parameter [RequestTimeout] is passed in the URL obey it (behaviour like CFML 5, 7 & 8)
- Application listener
- Sets how requests are handled and which templates are invoked by default.
- Mode
- Current
-
- Current tp root (CFML default)
- Root
- Defines where Lucee looks for the files "Application.cfc/Application.cfm". In case of type "none" this setting is meaningless.
- Looks for the file "Application.cfc/Application.cfm" only in the current template directory .
-
- Looks for the file "Application.cfc/Application.cfm" from the current up to the webroot directory.
- Looks for the file "Application.cfc/Application.cfm" only in the webroot .
- Type
- Classical (CFML < 7)
-
- Mixed (CFML >= 7)
- Modern
- None
- Please select the type of the listener
- Classic handling. Lucee looks for the file "Application.cfm" and a coresponding file "OnRequestEnd.cfm"
-
- Mixed handling. Lucee looks for a file "Application.cfm/OnRequestEnd.cfm" as well as for the file "Application.cfc"
- Modern handling. Lucee only looks for the file "Application.cfc"
- When a request is called no other initialization template will be invoked by Lucee
- Please select a value for script-protect
-
- Request timeout
- Sets the amount of time Lucee will wait for a request to finish before a request timeout will be raised. This means that the execution of the request will be stopped. This behaviour can be overridden by the tag cfsetting.
- Script-protect
- Script-protect checks in all scopes for external data (cgi,cookie,form,url)
- You can define the scopes to be checked individually
- The configuration of Script protect, secures your system from "cross-site scripting"
-
- Script-protect is not active
- Defines application settings that represent the default values for all webs
- Here you can define several default settings for the application context. These settings can be overridden with the tag cfapplication or the Application.cfc.
- assign archive to mapping
- cancel
- change
-
- compile
- create
- delete
- download archive
- execute
- filter
-
- install
- OK
- optimize
- purge
- repair
- reset
-
- save
- search
- setting
- submit
- uninstall
- update
-
- verify
- Java CFX tags
- Class
- Please enter a value for the class (row
- Name
- No access to CFX functionality
-
- Please specify a resource charset
- Please specify a template charset
- please specify a web charset
- Resource charset
- Default character set for reading from/writing to various resources
- Specify the default server character set
-
- Template charset
- Default character set for templates (*.cfm and *.cfc files)
- Specify the default server character set
- Web charset
- Default character set for output streams, form-, url-, and cgi scope variables and reading/writing the header
- Base/Root Component
-
- Every component that does not explicitly extend another component (attribute "extends") will by default extend this component. This means that every component extends this base component in some way.
- Please enter a value for the base/root component
- Component
- Component "dump" template
-
- If you call a component directly this template will be invoked to dump the component. (Example: https://www.lucee.org/ch/lucee/common/Example.cfc)
- Please enter a value for the "dump" template
- Data member access type
- Define the accessor for the data-members of a component. This defines how variables of the "this" scope of a component can be accessed from outside of the component.
-
- package
- private
- public (CFML standard)
- remote
- Define the component settings that will be used as a <strong>default</strong> for all webs.
-
- Magic functions
- If there is no accessible data member (property, element of the this scope) inside a component, Lucee searches for available matching "getters" or "setters" for the requested property.
- The following example should clarify this behaviour. "somevar = myComponent.properyName". If "myComponent" has no accessible data member named "propertyName",
- Lucee searches for a function member (method) named "getPropertyName".
-
- Variables scope
- Defines whether a component has an independent variables scope parallel to the "this" scope (CFML standard) or not.
- Defines how components will be handled by Lucee.
- Archive
- Please enter a value for the archive name (row
-
- Search subdirectories
- Search for custom tags in subdirectories (not supported for archives)
- Search local
- Search in the caller directory for the custom tag
- Resources
- Settings
-
- Resource
- Please enter a value for the resource (row
- Primary
- Trusted
- Debug template
- This template is used for formatting the debugging output
-
- Please enter a value for the debug template
- Enable debugging
- Enable or disable the debugging output
- Log memory usage
- Sets whether the memory usage should be logged
- Memory logger
-
- File the memory usage will be stored to
- Please enter a value for the timezone
- Type
- Description
- Only the number of arguments is rerstricted to {max}.
- It must have at least {min} arguments.
-
- It must have at least {min} arguments but a maximum of {max}.
- Name
- Required
- There is no restriction for this function regarding its arguments.
- The arguments for this function are set. You can not use other arguments except the following ones.
- This function has no arguments
-
- Arguments
- Type
- Description
- Only the number of attributes is restricted to {max}.
- This tag must have at keast {min} attributes.
- This tag must have at least {min} attributes but the most {max}.
-
- Name
- Required
- There is no restriction for attributes for this tag.
- The attributes for this tag are fixed. Except for the following attributes no other attributes are allowed.
- This tag has a fixed definition of attributes (see below). In addition it allows to use any additional attribute.
- This tag only allows one attribute value (no name).
-
- This tag has no attributes
- Attributes, supported by the tag.
- Attributes
- This tag may have a body.
- This tag can't have a body.
- This tag must have a body.
-
- Body
- Please enter an individual error template.
- Status code
- In case of an exception should an other status code be used or would it still be 200
- Missing Template Error (404)
- General Error Template (500)
-
- Template that will be invoked in case of a missing error. This setting can be overridden by the tag CFError.
- Template that will be invoked in case of an error. This setting can be overridden by the tag CFError.
- Day
- Days
- Hour
- The field "hour" must contain a positive integer
-
- Hours
- Minute
- The field "minute" must contain a positive integer
- Minutes
- Month
-
- No
- Second
- The field "second" must contain a positive integer
- Seconds
- Year
-
- Yes
- english (united kingdom)
- Change password
- Change the password for this administrator
- Set default password
- Set the default password for all web administrators
-
- New password
- The new password for the administrator
- Please enter a value for the new password
- The new password is to short, its length must be at least 6 characters
- Old password
- The old password to change
-
- Please enter a value for the old password
- The old password is to short, its length must be at least 6 characters
- Password
- Please enter a value for the field password
- Reset Password
- reset the Password of the selected Web
-
- Reenter the new password
- Please reenter the new password
- Retype new password
- Please reenter the password
- The new password and the reentered password are not the same
- Web
-
- Default encoding
-
- Log level
- Log file
- Missing value for mail log file
- Mail servers
-
- You can define more than one mail server. When sending a mail, Lucee tries to send the mail with the first defined mail server. If the send operation fails, Lucee will continue using the next mail server in the list.
- Please enter a value for the default encoding
- Password
- Please enter a value for the corresponding password (row
- Port
- Please enter a value for the port (row
-
- ) of type number
- Server (SMTP)
- Please enter a value for the mailserver (row
- Mail settings
- Spool enable
- Spool interval
-
- Timeout
- Username
- Please enter a value for the username (row
- Archive
- Generate a Lucee archive (ra) from an existing mapping
- Archive
-
- Name of the archive file (ra or ras), (absolute or relative to the webroot)
- Please enter a value for the archive name (row
- Secured
- Exclude source files from archive. Source files are only used for codeprints in case of an error
- create archive
- Compile all cfm and cfc files inside the mapping
-
- Stop on error
- Sets whether the compile process should be aborted on errors
- compile
- Here you can edit a certain mapping or create a Lucee archive out of an existing one.
- Please note, that only pages processed by Lucee are aware of these mappings (cfm, cfml, cfc). If you want to use files not processed by Lucee for these special mapping directories, you have to add virtual mappings to these directories to your application server.
- Resource
-
- Resource
- Path of the resource to map (absolute or relative to the webroot)
- Please enter a value for the resource (row
- Primary
- Sets where Lucee-files will first be searched
-
-
- Top Level
- Trusted
-
- Virtual
- Bug report
- bugs@lucee.ch
-
- ColdFusion® compatibilty version
- Contact
- Info
- Context count
- Lucee date/time
- Feature request
-
- features@lucee.ch
- Info
- info@lucee.ch
- Installed function<br/> libraries
- Installed tag<br/> libraries
-
- The server administrator allows you to install updates and patches for your Lucee edition and to restart the engine on mouseclick. If you have the Develop or Enterprise edition you can preconfigure new web contexts and define restrictions and configurations per web context individually.
- Lucee, the CFML engine. Fast, inexpensive and easy to use. By choosing Lucee you decided to go the performant and high quality way of CFML. Set up your local web context according to your needs and wishes. For this purpose you can use this Lucee web administrator.
- Available Editions
- Community
- Lucee Community is intended to be used by low budget business applicants. Except for some few limitations the Community Version offers the entire language range of Lucee.
- Lucee is available in four different editions , adapted to the different areas of application and budgets.
-
- Develop
- The Develop Version is a version, addressing those users who are most likely to apply it in order for assembling CFML appliction . The version though is prohibited to be used commercially.
- more
- Enterprise
- The Enterprise Version of Lucee is the biggest and most comprehensive version intended to be used in a larger context.
- Professional
-
- The Professional Version offers the full language range of Lucee, no restriction to the use of any feature has to be expected. With the Professional Version several webs can be used on one server, the number of webs however is limited by the licence price.
- OS
- Purchase your Lucee license
- Release date
- Sales
- sales@lucee.ch
-
- Serial number
- Serial number for Lucee
- Server date/time (mm/dd/yyyy HH:mm:ss):
- currently in use
- Version
- Do not use proxy
-
- Use proxy
- Please enter a value for the proxy port
- Password
- Password for the proxy
- Port
- Port for the proxy server (default:80)
-
- Define a global proxy, that will be used in several tags by default (cfhttp,cfftp,cfmail ...)
- URL of a proxy server eg."http://myproxyserver.org/"
- Proxy settings
- Username
- Username for the proxy
- Define a global proxy, that will be used in several tags by default (cfhttp,cfftp,cfmail ...)
-
- Default encoding
-
- Locale
- Define the desired time locale for Lucee, this will change the default locale for the context of the web.
- Please enter a value for the default encoding
- --- other ---
-
- Here you can define regional settings that will be used as a <strong>default</strong> for all webs. This settings have no direct effect on the current instance.
- Server properties
- Time server (NTP)
- Time server that returns the current time. If set, this time will be used within Lucee instead of the local server time. (Example: swisstime.ethz.ch, time.nist.gov)<br/>
-
- Please define a value for the field timezone
- Time zone
- Define the desired time zone for Lucee, this will also change the time for the context of the web.<br/>
- Lucee lets you set your own individual locale, timezone and timeserver.
- Admin Access
- Define Access to Remote Client, the Password and the Security Key, the Security key is provided by the Remote Client itself
-
- Password for the remote Server Administrator
- Password for the remote Web Administrator
- Password für the access to the remote Lucee Server Administrator
- Password für the access to the remote Lucee Web Administrator
- Connection
- Connection to the Remote Client, URL (with Port) and HTTP Access
-
- Here you can define clients, which will synchronize their settings with the ones of the current administrator
- Create Remote Client
-
- Update Remote Client
-
- When calling "<Buttons.downloadArchive>", the archive on the remote client will be created but the download ignored, In this case you shouln't include remote synchronization.
-
- Label
- The label for the remote client is missing
- List of the clients
- Create new remote client
- Action
- This task has been executed <tries> times. There are <triesleft> tries left
-
- Even after <tries> tries, this task couln't be executed properly
- Error messages
- Execution time
- 1-100 of <recordcount> open tasks
-
- Last execution
- Name
- Next execution
- Next execution in minutes
- There are currently no open tasks
- List of failed tasks. The tasks listed in green will be reexecuted. The ones in red have failed all attempts of executuion and wont be executed again.
-
- State
- Number of tries
- Number of remaining tries
- Type
- URL
- The Administrator password for the remote client is missing
-
- Proxy Settings
- Proxy Settings should be used for connection
- Password
- Port
- Proxy Server Port
- Server
-
- Proxy Server (Host)
- Username
- Security Key
- Please enter the key of the remote clients. You can find it under Remote security key in the administrator of the remote clients
- The security key for the remote client is missing
- In case this Web Administrator is to be synchronized by another server, you have to enter the security key below in the distant definition of the remote client.
-
- Password
- Http Access Auhtentication
- Username
- Http Access Auhtentication
- Define the clients that will be synchronized with the current administrator.
- Remote Client synchronization
-
- URL
- The remote client URL is missing
- Path
- Path to Admin.cfc (example: /lucee/admin.cfc?wsdl)
- the path to the Admin.cfc is missing
- Server
-
- Remote Client Server (Beispiel: http://lucee.ch)
- Remote Client Server
- Cluster Scope
- Define for what the Remote Client is used
- Admin Synchronisation
- Usage
-
- Create scheduled task
- Current date/time of this Lucee context is: (mm/dd/yyyy hh:mm tt)
- daily
- Here you can add, modify, run and delete scheduled tasks<br/><br/>
- Defined scheduled tasks
-
- The tasks displayed in red have expired and will no longer start.
- End date
- Ends at
- End time
- every
- Execute at
-
- Execution date/time
- Execution time
- File
- File the output is stored to
- Interval
- Interval in that the task will be executed
-
- Interval type
- Execution interval of the new task
- monthly
- Name
- URL that will be invoked by the task
- Name of the new task (this name must be unique)
-
- Please enter a value for the name of the task
- once
- Output
- Password
- Password to access the URL protected by authentication
- Port
-
- Port of the URL to call (HTTP Default: 80)
- Proxy settings
- Password to access the proxy protected by authentication
- Port of the proxy
- Username to access the proxy protected by authentication
- Publish
-
- Resolve URL
- Translate relative URLs into absolute
- Server
- Start date
- Starts at
- Start time
-
- Sets, whether the response of server will be stored in a file or not
- Timeout
- Timeout in seconds. Defines how long a task will wait for the response of the server called by the URL
- URL
- URL of the new task
- Please enter a value for the URL of the task
-
- Username
- Username to access the URL protected by authentication
- weekly
- Application timeout
- Sets the amount of time Lucee will keep the application scope alive. This behaviour can be overridden by the tag cfapplication.
- Search resultsets
-
- When a variable has no scope defined (Example: #myVar# instead of #variables.myVar#), Lucee will also search available resultsets (CFML Standard) or not
- Cascading
- Depending on this setting Lucee scans certain scopes to find a variable called from the CFML source. This will only happen, when the variable is called without a scope. (Example: #myVar# instead of #variables.myVar#)<br/>- strict: scans only the variables scope<br/>- small: scans the scopes variables,cgi,url,form<br/>- standard (CFML Standard): scans the scopes variables,cgi,url,form,cookie
- Client cookies
-
- Enable or disable client cookies. This behaviour can be overridden by the tag cfapplication.
- Client management
- By default client management can be enabled. This behaviour can be overridden by the tag cfapplication.
- Domain cookies
- Enable or disable domain cookies. This behaviour can be overridden by the tag cfapplication.
- Local scope mode
-
- always
- Defines how the local scope of a function is invoked when a variable with no scope definition is used.<br>
- - always: the local scope is always invoked<br>
- - update (CFML standard): the local scope is only invoked when the key already exists in it
- update (CFML standard)
- Merge URL and form
-
- This setting defines if the scopes URL and form will be merged together or not. CFML Default is false.
- Here you can define the scope settings that will be used as <strong>default</strong> for all webs.<br/>
- Session management
- By default session management can be enabled. This behaviour can be overridden by the tag cfapplication.
-
- Session timeout
- Sets the amount of time Lucee will keep the session scope alive. This behaviour can be overridden by the tag cfapplication.
- Session type
- Application
- JEE
- JEE Sessions allow you to make sessions over a cluster. When you change this setting, you will lose your current session, and you must make a new login.
-
- small
- standard (CFML Default)
- strict
- Value days for
- timeout must have an Integer Value
- Value hours for
-
- Value minutes for
- Value seconds for
- Here you can define the settings for how Lucee handles scopes.
- Collection
- Collections
- Create collection
-
- Here you can manage, create, populate and delete search collections. By default, lucee uses Apache Lucene as the search engine.<br/><br/>
- Directory path
- Please enter a path to be indexed
- External
- File extensions
-
- Please enter the file extensions to be indexed
- Index subdirectories
- Language
- Last update
- Mapped
- Please enter a name for the collection
-
- Please enter a valid path for the collection
- Name
- No Result for your criteria
- Online
- Path
- Add/Update path index
-
- Results {startrow} - {endrow} of about {recordcount} searched in {recordssearched} Records
- Results of the search
- Enter the searchterm
- Please enter a searchterm
- Search the collection
- URL
-
- Access Read
- define the access for reading data
- Access Write
- define the access for writing data
- CFML Environment
- Settings that have an effect on how Lucee code interacts with the host environment
-
- CFX
- The settings for the cfx tags can be changed. The globally defined CFX tags defined in the "server administrator" can be used as well.
- CFX tags
- With CFX tags one can load Java classes which might have full access to the local hosts system. This might be a potential security risk to the hosts system
- Custom Tag
-
- The custom tag settings can be changed in the "web administrator"
- Datasource
- Defines how many datasources can be added in the "web administrator".
- unlimited
- Debugging
-
- The debugging settings can be changed in the "web administrator"
- Define the access rights for the different web contextes (webapps). Under the "general" tab you define default rights for all web contexts that do not have a speficic definition in the "individual" tab.
- File access
- all
-
- Defines how Lucee can interact with the local filesystem in a web context.<br/>- none: allows no access to the filesystem at all<br/>- local: allows only access to the filesystem within the webroot<br/>- all: allows full file access on the hosts filesystem<br/>
- local
- none
- Tags & Functions
-
- Tags and Functions that might be a potential risk to the hosts system
- General Access
- Define the General Access for administrator and tag cfadmin
- Direct Java access
- Allows access to Java methods and properties from the Lucee code (Example: stringValue.substring(2,5)). Allowing access to Java methods and properties might be a potential security risk
- Mail
-
- The mail settings can be changed in the "web administrator"
- Mapping
- Allows adding, removing and updating of mappings in the "web administrator".
- Remote
- Es wird erlaubt das der User seine Einstellungen mit einem anderen lucee synchronisiern kann
-
- Scheduled task
- The scheduled task settings can be changed in the "web administrator"
- Search
- The search settings can be changed in the "web administrator"
- Settings (regional, component, scope)
-
- The settings (regional,component and scope) can be changed in the "web administrator"
- Define the security settings for a specific web context (webapps).
- Host name
- create new web context
- Path
- Security settings for a specific web context. You can edit or delete these contexts.
-
- specific web context
- Web context
- General
- Individual
- Tag CFExecute
- This tag is used to execute a process on the local hosts system
-
- Tag CFImport
- This tag can be used to import JSP and Lucee tag libraries
- Tag CFObject / <br/>function CreateObject
- With the tag CFObject and the function CreateObject you can load Java objects. If disabled, you only can create objects of type "component"
- Tag CFRegistry
-
- With the tag CFRegistry you have full access to the registry of the local hosts system
- Default access rights
- Here you can define the access rights that will be used as a default for all web contexts. If allowed, you can overwrite some of the settings in the corresponding "web administrator".
- Web administrator
- Here you can define the access rights for the settings that can be overridden in the "web administrator".
-
- You can patch Lucee in order to receive the latest bugfixes and improved version.
- Execute update
- Apply the latest patch for your version. After the update has been installed Lucee will be restarted, all sessions will be cleared and you have to login again.
- execute update
- Info
- URL
-
- Define the URL where Lucee gets its updates. Typically "https://www.lucee.org"
- For your version {current} is no patch available
- Remove updates
- Remove all installed updates.
- Remove updates
- Restart Lucee
-
- Restart the Lucee engine. All sessions will be cleared and you will have to login again.
- Define where Lucee gets its patches. You have to restart Lucee after the update in order for the changes to take effect.
- Properties
- Type
- Automatic
- Manual
-
- Define how Lucee will be patched. "Automatic" means that Lucee searches automatically for updates once a day. "Manual" means that you can update Lucee only manually here.
- A patch {available} is available for your current version {current}.
- Lucee output control
- Output Lucee version
-
- Return the Lucee version in the response header
- Lucee output control
- Whitespace management
- Removes all white spaces in the output that follow a white space
- Create new datasource connection
- Update datasource connection
-
- Create new datasource
- Settings
- Allowed operations
- Blob
- Enable binary large object retrieval (<abbr title="binary large object">BLOB</abbr>)
-
- Check
- Clob
- Enable long text retrieval (<abbr title="character large object">CLOB</abbr>)
- Connection limit (max)
- Restricts the maximum number of connections at one time
- - inf -
-
- Connection idle timeout (in minutes)
- Define how long an idle connection will be kept alive, before being closed
-
- Connection timeout
- Define how long a connection will be kept alive, before being closed
-
-
- Database
- Name of the database to connect
-
- Host/Server
- Host name where the database server is located
- Password
- The password for the database
- Port
- The port to connect the database
-
- Username
- The username for the database
- Datasources
- Name
- Please enter a name for the datasource
- Preserve single quotes
-
- Preserve single quotes (") in the SQL defined with the tag cfquery
- Readonly datasources
- Readonly datasources are generated within the "server administrator" for all web instances and can not be modified by the "web administrator".
- Type
-
- Provider
- URL of a provider offering the necessary (FFMpeg binaries) components.
- Missing provider definition
- The necessary video components are already installed on your system.
- The video components are installed but they can not be executed properly:
- A manual installation is recommended.
-
- For the tag cfvideo/cfvideoplayer OS specific video components are required. They are not bundled with Lucee because the size of the software would increase a lot and because some codecs may not be redistributed, although their use is not prohibited. Therefore you can download these components directly from a provider and upload them with the form below.
- The video components (ffmpeg.zip) are uploaded directly over the form and copied into Lucee (no installation). As a source you can use e.g. {provider}
- Video components by upload
- The video componenten are downloaded automatically from the remote server and copied into Lucee (no installation).
- Download video components by an URL
- A manuelle installation can be made like follows: Open the url {provider} and download the corresponding file ffmpeg.zip for your operating system ({OS-Name}). Then copy this file (do not unzip it) into the directory {directory}. If you can not find a file for your operating system, just contact us.
-
- Manual installation
- Upload
- Video components (ffmpeg.zip)
- Missing upload definition
- The video components are installed on your system.
- The video components are installed but they can not be executed properly.Just switch to the Lucee Server Administrator, in order to repair it:
-
- The video components are not installed on your system. In order to install them just switch to the Lucee Server Administrator.
-
-
-
-
diff --git a/core/src/main/cfml/context/admin/logout.cfm b/core/src/main/cfml/context/admin/logout.cfm
index 1de1168b7d..218094241c 100755
--- a/core/src/main/cfml/context/admin/logout.cfm
+++ b/core/src/main/cfml/context/admin/logout.cfm
@@ -1,5 +1,16 @@
-
-
-
-
-
\ No newline at end of file
+
+ StructDelete(application, "stText");
+ StructDelete(application, "UpdateProvider");
+ if(structKeyExists(url, "full")) {
+ systemOutput("=>"&request.adminType,1,1);
+ StructDelete(session,"passwordweb");
+ StructDelete(session,"passwordserver");
+ cookie expires="Now" name="lucee_admin_pw_web" value="";
+ cookie expires="Now" name="lucee_admin_pw_server" value="";
+ }
+ else {
+ StructDelete(session,"password"&request.adminType);
+ cookie expires="Now" name="lucee_admin_pw_#request.adminType#" value="";
+ }
+ location url="#cgi.SCRIPT_NAME#" addtoken="No";
+
\ No newline at end of file
diff --git a/core/src/main/cfml/context/admin/mvnchangeto.cfm b/core/src/main/cfml/context/admin/mvnchangeto.cfm
new file mode 100755
index 0000000000..cbc03530f5
--- /dev/null
+++ b/core/src/main/cfml/context/admin/mvnchangeto.cfm
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core/src/main/cfml/context/admin/overview.cfm b/core/src/main/cfml/context/admin/overview.cfm
index 5374d6815d..2514272088 100644
--- a/core/src/main/cfml/context/admin/overview.cfm
+++ b/core/src/main/cfml/context/admin/overview.cfm
@@ -18,7 +18,7 @@ Defaults --->
-
+
@@ -65,36 +65,71 @@ Redirect to entry --->
+
+
+
+
+
Warning Lucee Admin was compiled with version #lucee_version#?
+
+
+ stText.security.limitEvaluation="Limit variable evaluation in functions/tags";
+ stText.security.limitEvaluationDesc="If enable you cannot use expression within ""[ ]"" like this susi[getVariableName()] .
+ This affects the following functions [IsDefined, structGet, empty] and the following tags [savecontent attribute ""variable""].";
+
+
+
+
-
- SELECT functions FROM qryAllItems WHERE functions LIKE '#i#%';
+
+ SELECT functions FROM qryAllItems WHERE functions LIKE ?;
diff --git a/core/src/main/cfml/context/doc/tags.cfm b/core/src/main/cfml/context/doc/tags.cfm
index 1eb48d8dfc..d700a8ac1f 100644
--- a/core/src/main/cfml/context/doc/tags.cfm
+++ b/core/src/main/cfml/context/doc/tags.cfm
@@ -315,10 +315,11 @@
-
- SELECT tags FROM qryAllItems WHERE tags LIKE 'cf#i#%';
+
+ SELECT tags FROM qryAllItems WHERE tags LIKE ?;
+
@@ -343,4 +344,4 @@
-
\ No newline at end of file
+
diff --git a/core/src/main/cfml/context/gateway/AsynchronousEvents.cfc b/core/src/main/cfml/context/gateway/AsynchronousEvents.cfc
index 3ae8106562..4a38b2bc0b 100644
--- a/core/src/main/cfml/context/gateway/AsynchronousEvents.cfc
+++ b/core/src/main/cfml/context/gateway/AsynchronousEvents.cfc
@@ -1,4 +1,4 @@
-component accessors=true{
+component accessors=true {
this.logfile = "AsyncGateWay";
variables.state = "stopped";
@@ -26,8 +26,8 @@ component accessors=true{
variables.state == "error";
log text="Event Gateway #variables.id# error: #e.message#" file=this.logfile type="error";
}
- if ( variables.state == "running" && len(variables.config.interval) gt 0 )
- sleep( variables.config.interval );
+ if ( variables.state == "running" && len(variables.config.interval?:1000) gt 0 )
+ sleep(variables.config.interval?:1000);
}
variables.state = "stopped";
log text="Event Gateway #variables.id# stopped" file=this.logfile;
diff --git a/core/src/main/cfml/context/gateway/DirectoryWatcher.cfc b/core/src/main/cfml/context/gateway/DirectoryWatcher.cfc
index e34943b540..15be6ad8d7 100644
--- a/core/src/main/cfml/context/gateway/DirectoryWatcher.cfc
+++ b/core/src/main/cfml/context/gateway/DirectoryWatcher.cfc
@@ -350,9 +350,9 @@ component output="no" {
}
private void function logger( required string text, required string type="information" ) output=false {
- if ( arguments.type == "information" && !variables.verboseLogging )
+ if ( arguments.type == "information" && !(variables.verboseLogging?:true) )
return;
- local.stack = variables.verboseLogging ? ListLAst(ListGetAt(CallStackGet('string'),2,";"),"/\") : "";
+ local.stack = (variables.verboseLogging?:true) ? ListLAst(ListGetAt(CallStackGet('string'),2,";"),"/\") : "";
writeLog (
text="[#variables.id#, #getState()#] #arguments.text# #local.stack#",
file=variables.logFileName,
diff --git a/core/src/main/cfml/context/gateway/MailWatcher.cfc b/core/src/main/cfml/context/gateway/MailWatcher.cfc
index 7c4fd64a86..b678c0c1b7 100755
--- a/core/src/main/cfml/context/gateway/MailWatcher.cfc
+++ b/core/src/main/cfml/context/gateway/MailWatcher.cfc
@@ -29,7 +29,7 @@
public void function start() output=false localmode=true {
- while ( getState() EQ "stopping" ) {
+ if ( getState() EQ "stopping" ) {
sleep(10);
}
variables.state="running";
@@ -37,7 +37,7 @@
var last =now();
var mail = "";
- while ( variables.state EQ "running" ){
+ while ( variables.state EQ "running" ) {
try {
mails = getMailsNewerThan( config.server, config.port, config.username, config.password, config.attachmentpath, last);
for ( el in mails ) {
@@ -52,8 +52,10 @@
if ( getState() != "running" ) {
break;
}
- sleep( variables.config.interval );
+ sleep( variables.config.interval?:10 );
}
+ // set to stopped when we leave
+ variables.state = "stopped";
}
public array function getMailsNewerThan( required string server, required numeric port, required string user, required string pass,
@@ -86,6 +88,12 @@
public void function stop() output=false {
writeLog ( text="stop", file="MailWatcher", type="information" );
variables.state="stopping";
+
+ sleep( (variables.config.interval?:10)+10 );
+ // should be stopped, so we guess it is blockes somehow, because it will not run again, we can ignore it
+ if (getState() EQ "stopping" ) {
+ variables.state="stopped";
+ }
}
public void function restart() output=false {
diff --git a/core/src/main/cfml/context/res/css/admin6.css b/core/src/main/cfml/context/res/css/admin6.css
index 8f0f53cec0..bd24d1b7ec 100644
--- a/core/src/main/cfml/context/res/css/admin6.css
+++ b/core/src/main/cfml/context/res/css/admin6.css
@@ -1,10 +1,3 @@
-/*
-green:8bbf36;darker:81b72d;comment:c4de99;
-red:bf4f36;darker:b7492e;comment:dea598;
-blue:36afbf;darker:2da5b7;comment:99d6de;
-blue2:3399cc;darker:39c;comment:9acae5;
-*/
-
html, body {
min-height: 450px;
height: 100%;
@@ -24,7 +17,7 @@ body, td, th {
h1, h2, h3, h4, h5 {
font-weight:normal;
font-size : 18px;
- color:#666;
+ color:#5f8731;
margin:0;
padding:0 0 4px 0;
}
@@ -52,21 +45,23 @@ table + h3, div + h3 {
padding-top: 10px;
}
a {
- color:#36c;
+ color:#5f8731;
text-decoration:underline
}
tr > th > a {
- color: #ffffff !important;
+ color: #ffffff;
}
.admin-server a {
color:#bf4f36;
}
.admin-single a {
- color:#36c;
+ color:#5f8731;
+}
+.admin-web a {
+ color:#39c;
}
-
img, a img { border:0; }
form, div { margin:0; padding:0; }
@@ -160,7 +155,7 @@ body.server td#navtd {
box-shadow: 0px 0px 4px 1px #BF4F36;
}
body.single td#navtd {
- box-shadow: 0px 0px 4px 0px #9b99a3;
+ box-shadow: 0px 0px 4px 0px #5f8731;
}
td#logintd {
@@ -214,7 +209,7 @@ body.server #contenttd {
box-shadow: 0px 0px 4px 1px #BF4F36;
}
body.single #contenttd {
- box-shadow: 0px 0px 4px 0px #9b99a3;
+ box-shadow: 0px 0px 4px 1px #5f8731;
}
#content {
@@ -231,13 +226,13 @@ body.single #contenttd {
padding: 0px 0px 0px 0px;
text-align:center;
font-size : 8pt;
- color:#efede5;
+ color:#000;
}
#copyright a {
- color:#efede5;
+ color:#000;
}
.linkContext a {
- color:#36c;
+ /* color:#36c; */
text-decoration:none;
}
@@ -283,7 +278,7 @@ body.single #contenttd {
background-color: #C25201;
}
.admin-single #favorites:hover, .admin-server #favorites:focus {
- background-color: #36c;
+ background-color: #5f8731;
}
#favorites ul {
@@ -302,7 +297,7 @@ body.single #contenttd {
background-color: #C25201;
}
.admin-single #favorites ul {
- background-color: #36c;
+ background-color: #5f8731;
}
#favorites li {
list-style: none;
@@ -481,7 +476,7 @@ td.fieldPadded {
.admin-single th .comment,
.admin-single .extensionthumb .comment
-{color:#333;}
+{color:#5f8731;}
.important {
color:red !important;
@@ -535,7 +530,7 @@ div.ok {
.coding-tip {
display: none;
box-sizing: border-box;
- margin: 4rem 0.25rem 1rem 0.25rem;
+ margin: 0.25rem 0.25rem 1rem 0.25rem;
padding: 0.5rem;
border: 0px;
border-radius: 0.5em;
@@ -567,7 +562,7 @@ div.ok {
font-weight:normal;
font-family:Lato, Arial, Helvetica, sans-serif;
font-size : 18pt;
- color:#666;
+ color:#5f8731;
padding-top:40px;
}
@@ -638,7 +633,7 @@ input,select,textarea {
font-weight:bold;
font-size: 11px;
- background: #36c;
+ background: #5f8731;
box-shadow: 0px 2px 2px 0px #d9dade,
0px -2px 2px 0px #fcfcfc ;
@@ -782,7 +777,7 @@ label:hover {
}
.admin-single .radio {
- border-color:#36c;
+ border-color:#5f8731;
}
.radio:checked:after {
@@ -800,7 +795,7 @@ label:hover {
background: #b7492e;
}
.admin-single .radio:checked:after {
- background: #36c;
+ background: #5f8731;
}
@@ -819,7 +814,7 @@ label:hover {
border: 2px solid #b7492e;
}
.admin-single .checkbox {
- border: 2px solid #36c;
+ border: 2px solid #5f8731;
}
.checkbox:checked:after {
@@ -838,7 +833,7 @@ label:hover {
background: #b7492e;
}
.admin-single .checkbox:checked:after {
- background: #36c;
+ background: #5f8731;
}
@@ -964,7 +959,7 @@ body.server .box, body.server h1, body.server h2, body.server h3, body.server h4
{color:#999}
body.server #menu li ul li a:hover, body.server #menu li ul li a.menu_active
-{color:#36c}
+{color:#5f8731}
*/
@@ -1129,7 +1124,7 @@ tbody#extproviderlist td {
background-color:#BF4F36;
}
.admin-single .ribbon{
- background-color:#36c;
+ background-color:#5f8731;
}
.ribbon-left-wrapper {
@@ -1163,7 +1158,7 @@ tbody#extproviderlist td {
background-color:#BF4F36;
}
.admin-single .ribbon-left{
- background-color:#36c;
+ background-color:#5f8731;
}
.fLeft{
@@ -1346,7 +1341,7 @@ body.full #tr-header { height: 63px; }
#header { position: relative; height: 100px; -padding: 0 22px; -margin: 0 22px 0 22px; }
body.full #header { height: 68px; }
-#logo { display: block; position: absolute; top: -16px; left: 0; width: 186px; height: 68px;
+#logo { display: block; position: absolute; top: -16px; left: 0; width: 310px; height: 68px;
padding: 0;background-position: 0px -252px; }
body.full #logo { display: block; position: absolute; top: 0px; left: 0; width: 166px; height: 68px; padding: 0;
background-position: 0px -252px;width: 186px; }
diff --git a/core/src/main/cfml/context/res/img/admin6_sprite.png b/core/src/main/cfml/context/res/img/admin6_sprite.png
index 34143e8c74..ea8466ba4e 100644
Binary files a/core/src/main/cfml/context/res/img/admin6_sprite.png and b/core/src/main/cfml/context/res/img/admin6_sprite.png differ
diff --git a/core/src/main/cfml/context/templates/error/Application.cfc b/core/src/main/cfml/context/templates/error/Application.cfc
new file mode 100644
index 0000000000..7c402d16e3
--- /dev/null
+++ b/core/src/main/cfml/context/templates/error/Application.cfc
@@ -0,0 +1,14 @@
+component {
+ this.name="lucee-error-templates";
+ this.clientmanagement="no";
+ this.scriptprotect="all";
+ this.sessionmanagement="no";
+ this.setclientcookies="no";
+ this.setdomaincookies="no";
+ this.applicationtimeout="#createTimeSpan(0,0,5,0)#";
+
+ function onRequestStart( target ) {
+ setting showdebugoutput=false;
+ return false;
+ }
+}
diff --git a/core/src/main/java/META-INF/MANIFEST.MF b/core/src/main/java/META-INF/MANIFEST.MF
index 5083759c60..eba3787d63 100644
--- a/core/src/main/java/META-INF/MANIFEST.MF
+++ b/core/src/main/java/META-INF/MANIFEST.MF
@@ -9,8 +9,9 @@ Multi-Release: true
Require-Bundle-Fragment: slf4j.nop;bundle-version=1.7.36
Bundle-ManifestVersion: 2
Bundle-SymbolicName: lucee.core
+Bundle-ClassPath: .,META-INF/
Import-Package: coldfusion.xml.rpc,com.allaire.cfx,
- com.intergral.fusiondebug.server,com.sun.management,com.sun.mail.smtp,com.sun.net.ssl.internal.ssl,
+ com.intergral.fusiondebug.server,com.sun.management,com.sun.net.ssl.internal.ssl,
javax.el,javax.servlet,javax.servlet.jsp,javax.servlet.http,javax.script,javax.activation,
javax.imageio,javax.imageio.metadata,javax.imageio.stream,javax.imageio.plugins.jpeg,
javax.management,javax.naming,javax.naming.directory,javax.net.ssl,
@@ -29,8 +30,8 @@ Export-Package: coldfusion,
org.objectweb,
org.objectweb.asm,
org.opencfml,
- org.opencfml.cfx,
lucee,
+ org.opencfml.cfx,
lucee.commons,
lucee.commons.activation,
lucee.commons.cli,
@@ -171,7 +172,6 @@ Export-Package: coldfusion,
lucee.runtime.functions.string,
lucee.runtime.functions.struct,
lucee.runtime.functions.system,
- lucee.runtime.functions.video,
lucee.runtime.functions.xml,
lucee.runtime.gateway,
lucee.runtime.gateway.proxy,
@@ -279,7 +279,6 @@ Export-Package: coldfusion,
lucee.runtime.user,
lucee.runtime.util,
lucee.runtime.util.pool,
- lucee.runtime.video,
lucee.runtime.vm,
lucee.runtime.writer,
lucee.servlet,
@@ -318,7 +317,7 @@ Export-Package: coldfusion,
lucee.transformer.cfml.script.java.function
Require-Bundle: org.apache.commons.commons-codec;bundle-version=1.15.0,
org.apache.commons.commons-collections4;bundle-version=4.4.0,
- org.apache.commons.commons-compress;bundle-version=1.23.0,
+ org.apache.commons.commons-compress;bundle-version=1.24.0,
org.apache.commons.commons-fileupload;bundle-version=1.5.0,
org.apache.commons.commons-io;bundle-version=2.11.0,
org.apache.commons.lang3;bundle-version=3.12.0,
@@ -339,7 +338,7 @@ Require-Bundle: org.apache.commons.commons-codec;bundle-version=1.15.0,
org.lucee.httpcomponents.httpclient;bundle-version=4.5.13,
org.lucee.httpcomponents.httpcore;bundle-version=4.4.13,
org.lucee.httpcomponents.httpmime;bundle-version=4.5.13,
- hsqldb;bundle-version=1.8.0,
+ org.lucee.hsqldb;bundle-version=2.7.2.jdk8,
jacob;bundle-version=1.16.1,
javasysmon;bundle-version=0.3.3,
jcifs;bundle-version=1.3.17,
@@ -348,29 +347,26 @@ Require-Bundle: org.apache.commons.commons-codec;bundle-version=1.15.0,
org.objectweb.asm.all;bundle-version=4.2,
org.lucee.xml.resolver;bundle-version=1.2.0,
slf4j.api;bundle-version=1.7.36,
- ss.css2;bundle-version=0.9.4,
- stax.api;bundle-version=1.0.1.0002L,
- javax.mail.activation;bundle-version=1.6.2.0000L,
- sun.security.jaas;bundle-version=1.2.4,
+ org.lucee.commons-email-all;bundle-version=1.6.0,
tagsoup;bundle-version=1.2.1.0002L,
w3c.dom;bundle-version=1.1.0,
- org.lucee.commons.email;bundle-version=1.2.0,
- com.github.mwiede.jsch;bundle-version=0.2.8,
+ com.github.mwiede.jsch;bundle-version=0.2.11,
org.lucee.jzlib;bundle-version=1.1.3,
- xmpcore;bundle-version=5.1.2.0002L,
org.lucee.argon2;bundle-version=2.7.0,
com.sun.jna;bundle-version=5.13.0,
- org.lucee.txtmark;bundle-version=0.16.0
-Require-Extension: 7E673D15-D87C-41A6-8B5F1956528C605F;name=MySQL;label=MySQL;version=8.0.30,
- 99A4EF8D-F2FD-40C8-8FB8C2E67A4EEEB6;name=MSSQL;label=MS SQL Server;version=7.2.2.jre8,
- 671B01B8-B3B3-42B9-AC055A356BED5281;name=PostgreSQL;label=PostgreSQL;version=42.2.20,
+ org.lucee.txtmark;bundle-version=0.16.0,
+ com.github.f4b6a3.ulid;bundle-version=5.2.3,
+ org.lucee.janino;bundle-version=3.1.9,
+ org.lucee.janinocc;bundle-version=3.1.9
+Require-Extension: 7E673D15-D87C-41A6-8B5F1956528C605F;name=MySQL;label=MySQL;version=8.1.0,
+ 99A4EF8D-F2FD-40C8-8FB8C2E67A4EEEB6;name=MSSQL;label=MS SQL Server;version=12.2.0.jre8,
+ 671B01B8-B3B3-42B9-AC055A356BED5281;name=PostgreSQL;label=PostgreSQL;version=42.6.0,
2BCD080F-4E1E-48F5-BEFE794232A21AF6;name=JDTsSQL;label=jTDS (MSSQL);version=1.3.1,
CED6227E-0F49-6367-A68D21AACA6B07E8;name=Admin;label=Lucee Administrator;version=1.0.0.5,
D46D49C3-EB85-8D97-30BEC2F38561E985;name=Doc;label=Lucee Documentation;version=1.0.0.4,
- 17AB52DE-B300-A94B-E058BD978511E39E;name=S3;label=S3;version=2.0.0.101-RC,
- 87FE44E5-179C-43A3-A87B3D38BEF4652E;name=EHCache;label=EHCache;version=2.10.0.35-SNAPSHOT,
- FAD1E8CB-4F45-4184-86359145767C29DE;name=Hibernate;label=Hibernate;version=5.4.29.20-BETA,
- 66E312DD-D083-27C0-64189D16753FD6F0;name=PDF;label=PDF;version=1.1.0.19,
- B737ABC4-D43F-4D91-8E8E973E37C40D1B;name=Image;label=Image;version=2.0.0.23-RC;since=5.3.0.35-ALPHA,
- 37C61C0A-5D7E-4256-8572639BE0CF5838;name=Esapi;label=ESAPI;version=2.2.4.13-SNAPSHOT;since=5.3.0.37-ALPHA,
- 8D7FB0DF-08BB-1589-FE3975678F07DB17;name=Compress;label=Compress;version=1.0.0.14-SNAPSHOT;since=5.3.2.31-SNAPSHOT
+ 17AB52DE-B300-A94B-E058BD978511E39E;name=S3;label=S3;version=2.0.1.15,
+ 87FE44E5-179C-43A3-A87B3D38BEF4652E;name=EHCache;label=EHCache;version=2.10.0.36,
+ 66E312DD-D083-27C0-64189D16753FD6F0;name=PDF;label=PDF;version=1.2.0.10-RC,
+ B737ABC4-D43F-4D91-8E8E973E37C40D1B;name=Image;label=Image;version=2.0.0.26-RC;since=5.3.0.35-ALPHA,
+ 37C61C0A-5D7E-4256-8572639BE0CF5838;name=Esapi;label=ESAPI;version=2.2.4.15;since=5.3.0.37-ALPHA,
+ 8D7FB0DF-08BB-1589-FE3975678F07DB17;name=Compress;label=Compress;version=1.0.0.15;since=5.3.2.31-SNAPSHOT
diff --git a/core/src/main/java/coldfusion/image/Image.java b/core/src/main/java/coldfusion/image/Image.java
index 540af4ff6f..9a2e06e679 100644
--- a/core/src/main/java/coldfusion/image/Image.java
+++ b/core/src/main/java/coldfusion/image/Image.java
@@ -23,8 +23,7 @@
import java.awt.RenderingHints.Key;
import java.awt.image.BufferedImage;
-import javax.servlet.jsp.PageContext;
-
+import lucee.runtime.PageContext;
import lucee.runtime.type.Struct;
public interface Image {
diff --git a/core/src/main/java/lucee/aprint.java b/core/src/main/java/lucee/aprint.java
index e788ce547c..7c50e2a19d 100755
--- a/core/src/main/java/lucee/aprint.java
+++ b/core/src/main/java/lucee/aprint.java
@@ -46,6 +46,7 @@
import lucee.commons.io.res.Resource;
import lucee.commons.io.res.ResourcesImpl;
import lucee.commons.io.res.util.ResourceUtil;
+import lucee.commons.lang.SystemOut;
import lucee.runtime.engine.CFMLEngineImpl;
import lucee.runtime.exp.PageException;
import lucee.runtime.op.Caster;
@@ -55,10 +56,12 @@
*
*/
public class aprint {
+ public static void edate(String value) {
+ e(SystemOut.FORMAT.format(new Date(System.currentTimeMillis())) + " " + value);
+ }
public static void date(String value) {
- long millis = System.currentTimeMillis();
- o(new Date(millis) + "-" + (millis - (millis / 1000 * 1000)) + " " + value);
+ o(SystemOut.FORMAT.format(new Date(System.currentTimeMillis())) + " " + value);
}
public static void ds(boolean useOutStream) {
diff --git a/core/src/main/java/lucee/commons/collection/Hashing.java b/core/src/main/java/lucee/commons/collection/Hashing.java
index c11f5fb9e2..c0d2609893 100644
--- a/core/src/main/java/lucee/commons/collection/Hashing.java
+++ b/core/src/main/java/lucee/commons/collection/Hashing.java
@@ -216,8 +216,8 @@ private static class Holder {
*
* We try to improve upon the default seeding.
*/
- static final Random SEED_MAKER = new Random(Double.doubleToRawLongBits(ThreadLocalRandom.current().nextDouble()) ^ System.identityHashCode(Hashing.class) ^ System.currentTimeMillis()
- ^ System.nanoTime() ^ Runtime.getRuntime().freeMemory());
+ static final Random SEED_MAKER = new Random(Double.doubleToRawLongBits(ThreadLocalRandom.current().nextDouble()) ^ System.identityHashCode(Hashing.class)
+ ^ System.currentTimeMillis() ^ System.nanoTime() ^ Runtime.getRuntime().freeMemory());
/**
* Access to {@code String.hash32()}
diff --git a/core/src/main/java/lucee/commons/color/ColorCaster.java b/core/src/main/java/lucee/commons/color/ColorCaster.java
index 264eb83b82..705193a82e 100644
--- a/core/src/main/java/lucee/commons/color/ColorCaster.java
+++ b/core/src/main/java/lucee/commons/color/ColorCaster.java
@@ -20,8 +20,6 @@
import java.awt.Color;
-import javax.servlet.ServletException;
-
import lucee.commons.lang.NumberUtil;
import lucee.commons.lang.StringUtil;
import lucee.runtime.exp.ExpressionException;
@@ -38,7 +36,7 @@ public final class ColorCaster {
* @return an int between 0 (badest) and 510 (best)
* @throws ServletException
*/
- public static int contrast(Color left, Color right) throws ServletException {
+ public static int contrast(Color left, Color right) {
return (Math.max(left.getRed(), right.getRed()) - Math.min(left.getRed(), right.getRed()))
+ (Math.max(left.getGreen(), right.getGreen()) - Math.min(left.getGreen(), right.getGreen()))
+ (Math.max(left.getBlue(), right.getBlue()) - Math.max(left.getBlue(), right.getBlue()));
diff --git a/core/src/main/java/lucee/commons/cpu/CFMLListener.java b/core/src/main/java/lucee/commons/cpu/CFMLListener.java
index 72aac3c26c..76ab02b751 100644
--- a/core/src/main/java/lucee/commons/cpu/CFMLListener.java
+++ b/core/src/main/java/lucee/commons/cpu/CFMLListener.java
@@ -16,7 +16,6 @@
import lucee.runtime.exp.PageException;
import lucee.runtime.thread.ThreadUtil;
import lucee.runtime.type.Collection.Key;
-import lucee.runtime.type.KeyImpl;
import lucee.runtime.type.QueryImpl;
import lucee.runtime.type.StructImpl;
import lucee.runtime.type.util.KeyConstants;
@@ -53,7 +52,7 @@ public final void listen(List list) {
}
}
- private static final Key PERCENTAGE = KeyImpl.getInstance("percentage");
+ private static final Key PERCENTAGE = KeyConstants._percentage;
private static final Key[] columns = new Key[] { KeyConstants._name, PERCENTAGE, KeyConstants._stacktrace, KeyConstants._time, KeyConstants._total };
protected Object toQuery(List list) throws PageException {
diff --git a/core/src/main/java/lucee/commons/i18n/FormatUtil.java b/core/src/main/java/lucee/commons/i18n/FormatUtil.java
index 9e67f8f244..c0faec8607 100644
--- a/core/src/main/java/lucee/commons/i18n/FormatUtil.java
+++ b/core/src/main/java/lucee/commons/i18n/FormatUtil.java
@@ -277,7 +277,8 @@ public static DateFormat[] getCFMLFormats(TimeZone tz, boolean lenient) {
new SimpleDateFormat("EEE d, MMM yyyy HH:mm:ss zz", Locale.ENGLISH), new SimpleDateFormat("dd-MMM-yyyy", Locale.ENGLISH),
new SimpleDateFormat("MMMM, dd yyyy HH:mm:ssZ", Locale.ENGLISH), new SimpleDateFormat("MMMM, dd yyyy HH:mm:ss", Locale.ENGLISH),
new SimpleDateFormat("yyyy/MM/dd HH:mm:ss zz", Locale.ENGLISH), new SimpleDateFormat("dd MMM yyyy HH:mm:ss zz", Locale.ENGLISH),
- new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss 'GMT'ZZ (z)", Locale.ENGLISH), new SimpleDateFormat("dd MMM, yyyy HH:mm:ss", Locale.ENGLISH)
+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss zz", Locale.ENGLISH), new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss 'GMT'ZZ (z)", Locale.ENGLISH),
+ new SimpleDateFormat("dd MMM, yyyy HH:mm:ss", Locale.ENGLISH)
// ,new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss",Locale.ENGLISH)
};
diff --git a/core/src/main/java/lucee/commons/img/AbstractCaptcha.java b/core/src/main/java/lucee/commons/img/AbstractCaptcha.java
index 361d02c370..17c731ca5e 100644
--- a/core/src/main/java/lucee/commons/img/AbstractCaptcha.java
+++ b/core/src/main/java/lucee/commons/img/AbstractCaptcha.java
@@ -18,8 +18,6 @@
**/
package lucee.commons.img;
-import java.util.concurrent.ThreadLocalRandom;
-
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
@@ -33,6 +31,7 @@
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.ThreadLocalRandom;
/**
* Abstract template class for captcha generation
diff --git a/core/src/main/java/lucee/commons/io/IOUtil.java b/core/src/main/java/lucee/commons/io/IOUtil.java
index d0f0b49d94..6ea6c77af6 100644
--- a/core/src/main/java/lucee/commons/io/IOUtil.java
+++ b/core/src/main/java/lucee/commons/io/IOUtil.java
@@ -39,6 +39,8 @@
import java.lang.reflect.Method;
import java.net.URL;
import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
@@ -61,6 +63,8 @@
*/
public final class IOUtil {
+ private static final int DEFAULT_BLOCK_SIZE = 0xffff;// 65535
+
/**
* copy an inputstream to an outputstream
*
@@ -72,7 +76,7 @@ public final class IOUtil {
*/
public static final void copy(InputStream in, OutputStream out, boolean closeIS, boolean closeOS) throws IOException {
try {
- copy(in, out, 0xffff);// 65535
+ copy(in, out, DEFAULT_BLOCK_SIZE);
}
finally {
if (closeIS && closeOS) close(in, out);
@@ -85,7 +89,7 @@ public static final void copy(InputStream in, OutputStream out, boolean closeIS,
public static final void copy(InputStream in, OutputStream out, int blockSize, boolean closeIS, boolean closeOS) throws IOException {
try {
- copy(in, out, blockSize);// 65535
+ copy(in, out, blockSize);
}
finally {
if (closeIS && closeOS) close(in, out);
@@ -107,7 +111,7 @@ public static final void copy(InputStream in, OutputStream out, int blockSize, b
*/
public static final void merge(InputStream in1, InputStream in2, OutputStream out, boolean closeIS1, boolean closeIS2, boolean closeOS) throws IOException {
try {
- merge(in1, in2, out, 0xffff);
+ merge(in1, in2, out, DEFAULT_BLOCK_SIZE);
}
finally {
if (closeIS1) closeEL(in1);
@@ -197,13 +201,13 @@ public static void copy(Resource in, OutputStream os, boolean closeOS) throws IO
}
public static final void copy(InputStream in, OutputStream out, int offset, int length) throws IOException {
- copy(in, out, offset, length, 0xffff);
+ copy(in, out, offset, length, DEFAULT_BLOCK_SIZE);
}
public static final void copy(InputStream in, OutputStream out, long offset, long length) throws IOException {
int len;
byte[] buffer;
- int block = 0xffff;
+ int block = DEFAULT_BLOCK_SIZE;
// first offset to start
if (offset > 0) {
@@ -250,7 +254,7 @@ public static final void copy(InputStream in, OutputStream out, int offset, int
int len;
byte[] buffer;
- int block;// 0xffff;
+ int block;
// first offset to start
if (offset > 0) {
@@ -264,7 +268,7 @@ public static final void copy(InputStream in, OutputStream out, int offset, int
}
if (skipped <= 0) {
- block = blockSize;// 0xffff;
+ block = blockSize;
while (true) {
if (block > offset) block = offset;
buffer = new byte[block];
@@ -282,7 +286,7 @@ public static final void copy(InputStream in, OutputStream out, int offset, int
copy(in, out, blockSize);
return;
}
- block = blockSize;// 0xffff;
+ block = blockSize;
while (true) {
if (block > length) block = length;
buffer = new byte[block];
@@ -321,7 +325,7 @@ private static final void copy(InputStream in, OutputStream out, int blockSize)
* @throws IOException
*/
public static final boolean copyMax(InputStream in, OutputStream out, long max) throws IOException {
- byte[] buffer = new byte[0xffff];
+ byte[] buffer = new byte[DEFAULT_BLOCK_SIZE];
int len;
long total = 0;
while ((len = in.read(buffer)) != -1) {
@@ -348,7 +352,7 @@ private static final void merge(InputStream in1, InputStream in2, OutputStream o
* @throws IOException
*/
private static final void copy(Reader r, Writer w, long timeout) throws IOException {
- copy(r, w, 0xffff, timeout);
+ copy(r, w, DEFAULT_BLOCK_SIZE, timeout);
}
/**
@@ -362,7 +366,7 @@ private static final void copy(Reader r, Writer w, long timeout) throws IOExcept
*/
public static final void copy(Reader reader, Writer writer, boolean closeReader, boolean closeWriter) throws IOException {
try {
- copy(reader, writer, 0xffff, -1);
+ copy(reader, writer, DEFAULT_BLOCK_SIZE, -1);
}
finally {
if (closeReader && closeWriter) close(reader, writer);
@@ -1417,4 +1421,14 @@ public void run() {
}
}
}
+
+ public static void deleteEL(Path path) {
+ if (path != null) {
+ try {
+ Files.delete(path);
+ }
+ catch (Exception e) {
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/core/src/main/java/lucee/commons/io/SystemUtil.java b/core/src/main/java/lucee/commons/io/SystemUtil.java
index cc4a3e17c6..d28092f598 100644
--- a/core/src/main/java/lucee/commons/io/SystemUtil.java
+++ b/core/src/main/java/lucee/commons/io/SystemUtil.java
@@ -57,6 +57,7 @@
import javax.servlet.ServletContext;
+import org.apache.felix.framework.BundleWiringImpl.BundleClassLoader;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleReference;
@@ -1388,10 +1389,19 @@ public static String getLocalHostName() {
public static InputStream getResourceAsStream(Bundle bundle, String path) {
// check the bundle for the resource
InputStream is;
+ if (bundle == null) {
+ ClassLoader cl = PageSourceImpl.class.getClassLoader();
+ if (cl instanceof BundleClassLoader) {
+ bundle = ((BundleClassLoader) cl).getBundle();
+ }
+ }
if (bundle != null) {
try {
is = bundle.getEntry(path).openStream();
if (is != null) return is;
+ if (path.startsWith("/")) is = bundle.getEntry(path.substring(1)).openStream();
+ if (is != null) return is;
+
}
catch (Throwable t) {
ExceptionUtil.rethrowIfNecessary(t);
@@ -1403,6 +1413,8 @@ public static InputStream getResourceAsStream(Bundle bundle, String path) {
try {
is = cl.getResourceAsStream(path);
if (is != null) return is;
+ if (path.startsWith("/")) is = cl.getResourceAsStream(path.substring(1));
+ if (is != null) return is;
}
catch (Throwable t) {
ExceptionUtil.rethrowIfNecessary(t);
@@ -1413,6 +1425,8 @@ public static InputStream getResourceAsStream(Bundle bundle, String path) {
try {
is = cl.getResourceAsStream(path);
if (is != null) return is;
+ if (path.startsWith("/")) is = cl.getResourceAsStream(path.substring(1));
+ if (is != null) return is;
}
catch (Throwable t) {
ExceptionUtil.rethrowIfNecessary(t);
@@ -1423,6 +1437,8 @@ public static InputStream getResourceAsStream(Bundle bundle, String path) {
try {
is = cl.getResourceAsStream(path);
if (is != null) return is;
+ if (path.startsWith("/")) is = cl.getResourceAsStream(path.substring(1));
+ if (is != null) return is;
}
catch (Throwable t) {
ExceptionUtil.rethrowIfNecessary(t);
diff --git a/core/src/main/java/lucee/commons/io/log/log4j2/Log4j2Engine.java b/core/src/main/java/lucee/commons/io/log/log4j2/Log4j2Engine.java
index 2edc4630b7..05280b54f6 100644
--- a/core/src/main/java/lucee/commons/io/log/log4j2/Log4j2Engine.java
+++ b/core/src/main/java/lucee/commons/io/log/log4j2/Log4j2Engine.java
@@ -3,8 +3,10 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.Charset;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
@@ -34,12 +36,14 @@
import lucee.commons.io.log.log4j2.appender.TaskAppender;
import lucee.commons.io.log.log4j2.layout.ClassicLayout;
import lucee.commons.io.log.log4j2.layout.DataDogLayout;
+import lucee.commons.io.log.log4j2.layout.JsonLayout;
import lucee.commons.io.log.log4j2.layout.XMLLayout;
import lucee.commons.io.res.Resource;
import lucee.commons.io.res.util.ResourceUtil;
import lucee.commons.io.retirement.RetireListener;
import lucee.commons.lang.ClassUtil;
import lucee.commons.lang.StringUtil;
+import lucee.loader.util.Util;
import lucee.runtime.config.Config;
import lucee.runtime.config.ConfigWeb;
import lucee.runtime.config.ConfigWebUtil;
@@ -50,6 +54,7 @@
import lucee.runtime.op.Caster;
import lucee.runtime.reflection.Reflector;
import lucee.runtime.reflection.pairs.MethodInstance;
+import lucee.runtime.type.util.ListUtil;
import lucee.transformer.library.ClassDefinitionImpl;
public class Log4j2Engine extends LogEngine {
@@ -140,6 +145,10 @@ public ClassDefinition> layoutClassDefintion(String className) {
|| "org.apache.logging.log4j.core.layout.XmlLayout".equalsIgnoreCase(className) || "lucee.commons.io.log.log4j2.layout.XMLLayout".equals(className)) {
return new ClassDefinitionImpl(XMLLayout.class);
}
+ if ("json".equalsIgnoreCase(className) || "org.apache.log4j.json.JsonTemplateLayout".equalsIgnoreCase(className)
+ || "org.apache.logging.log4j.core.layout.JsonLayout".equalsIgnoreCase(className)) {
+ return new ClassDefinitionImpl(JsonLayout.class);
+ }
if ("pattern".equalsIgnoreCase(className) || "org.apache.log4j.PatternLayout".equals(className) || "org.apache.logging.log4j.core.layout.PatternLayout".equals(className)) {
return new ClassDefinitionImpl(PatternLayout.class);
}
@@ -174,7 +183,7 @@ public ClassDefinition> layoutClassDefintion(String className) {
@Override
public final Object getLayout(ClassDefinition cd, Map layoutArgs, ClassDefinition cdAppender, String name) throws PageException {
if (layoutArgs == null) layoutArgs = new HashMap();
-
+ lowerCase(layoutArgs);
// Layout
Layout layout = null;
@@ -199,20 +208,22 @@ else if (HtmlLayout.class.getName().equalsIgnoreCase(cd.getClassName())) {
layoutArgs.put("title", title);
// font name
- String fontName = Caster.toString(layoutArgs.get("fontName"), "");
+ String fontName = Caster.toString(layoutArgs.get("fontname"), "");
if (!StringUtil.isEmpty(fontName, true)) builder.withFontName(fontName);
- layoutArgs.put("fontName", fontName);
+ layoutArgs.put("fontname", fontName);
// font size
- FontSize fontSize = toFontSize(Caster.toString(layoutArgs.get("fontSize"), null));
+ FontSize fontSize = toFontSize(Caster.toString(layoutArgs.get("fontsize"), null));
if (fontSize != null) builder.withFontSize(fontSize);
- layoutArgs.put("fontSize", fontSize == null ? "" : fontSize.name());
+ layoutArgs.put("fontsize", fontSize == null ? "" : fontSize.name());
layout = builder.build();
}
// XML Layout
else if (XMLLayout.class.getName().equalsIgnoreCase(cd.getClassName())) {
+ // Charset
+ Charset charset = CharsetUtil.toCharset(layoutArgs.get("charset"), CharsetUtil.UTF8);
// Location Info
boolean locInfo = Caster.toBooleanValue(layoutArgs.get("locationinfo"), false);
@@ -223,9 +234,42 @@ else if (XMLLayout.class.getName().equalsIgnoreCase(cd.getClassName())) {
layoutArgs.put("properties", props.toString());
// TODO add more attribute
- return new XMLLayout(CharsetUtil.UTF8, true, locInfo);
+ return new XMLLayout(charset, true, locInfo);
+ }
+ // JSON Layout
+ else if (JsonLayout.class.getName().equalsIgnoreCase(cd.getClassName())) {
+ // enviroment variables
+ String[] envNames = null;
+ String tmp = layoutArgs.get("envnames");
+ if (!StringUtil.isEmpty(tmp, true)) {
+ List list = ListUtil.listToList(tmp, ',', true);
+ List list2 = new ArrayList<>();
+ for (String el: list) {
+ if (!StringUtil.isEmpty(el, true)) list2.add(el);
+ }
+ if (!list2.isEmpty()) envNames = list2.toArray(new String[list2.size()]);
+ }
+ // charset
+ Charset charset = CharsetUtil.toCharset(layoutArgs.get("charset"), CharsetUtil.UTF8);
+ // complete
+ boolean complete = Caster.toBooleanValue(layoutArgs.get("complete"), false);
+ // includeStacktrace
+ boolean includeStacktrace = Caster.toBooleanValue(layoutArgs.get("includestacktrace"), true);
+ // includeTimeMillis
+ boolean includeTimeMillis = Caster.toBooleanValue(layoutArgs.get("includetimemillis"), true);
+ // stacktraceAsString
+ boolean stacktraceAsString = Caster.toBooleanValue(layoutArgs.get("stacktraceasstring"), false);
+ // locationInfo
+ boolean locationInfo = Caster.toBooleanValue(layoutArgs.get("locationinfo"), false);
+ // properties
+ boolean properties = Caster.toBooleanValue(layoutArgs.get("properties"), true);
+ // compact
+ boolean compact = Caster.toBooleanValue(layoutArgs.get("compact"), false);
+
+ return new JsonLayout(charset, complete, compact, includeStacktrace, includeTimeMillis, stacktraceAsString, locationInfo, properties, envNames);
}
+
// Pattern Layout
else if (PatternLayout.class.getName().equalsIgnoreCase(cd.getClassName())) {
org.apache.logging.log4j.core.layout.PatternLayout.Builder builder = PatternLayout.newBuilder();
@@ -358,7 +402,7 @@ else if (ResourceAppender.class.getName().equalsIgnoreCase(cd.getClassName())) {
path = path.trim();
path = ConfigWebUtil.translateOldPath(path);
res = ConfigWebUtil.getFile(config, config.getConfigDir(), path, ResourceUtil.TYPE_FILE);
- if (res.isDirectory()) {
+ if (res != null && res.isDirectory()) {
res = res.getRealResource(name + ".log");
}
}
@@ -602,4 +646,23 @@ private static Appender getFallback(Config config) {
}
return fallback;
}
+
+ private static void lowerCase(Map map) {
+ String v;
+ for (String k: map.keySet()) {
+ if (hasUpperCase(k)) {
+ v = map.get(k);
+ map.put(k.toLowerCase(), v);
+ map.remove(k);
+ }
+ }
+ }
+
+ private static boolean hasUpperCase(String str) {
+ if (Util.isEmpty(str, true)) return false;
+ for (int i = str.length() - 1; i >= 0; i--) {
+ if (Character.isUpperCase(str.charAt(i))) return true;
+ }
+ return false;
+ }
}
diff --git a/core/src/main/java/lucee/commons/io/log/log4j2/appender/ResourceAppender.java b/core/src/main/java/lucee/commons/io/log/log4j2/appender/ResourceAppender.java
index 5cdf29490b..d656061dfd 100644
--- a/core/src/main/java/lucee/commons/io/log/log4j2/appender/ResourceAppender.java
+++ b/core/src/main/java/lucee/commons/io/log/log4j2/appender/ResourceAppender.java
@@ -47,11 +47,18 @@ public ResourceAppender(String name, Filter filter, Layout layout, Resource res,
this.maxFileSize = maxFileSize;
this.maxfiles = maxfiles;
this.token = SystemUtil.createToken("ResourceAppender", res.getAbsolutePath());
- setFile(append, true);
+
}
@Override
public void append(LogEvent event) {
+ try {
+ setFile(append, true);
+ }
+ catch (IOException ioe) {
+ LogUtil.logGlobal(ThreadLocalPageContext.getConfig(), "log-loading", "Unable to write to" + res, ioe);
+ }
+
start();
// check file length
if (size > maxFileSize) {
@@ -96,6 +103,12 @@ public void append(LogEvent event) {
}
}
+ @Override
+ public void stop() {
+ closeFile();
+ super.stop();
+ }
+
/**
*
* Sets and opens the file where the log output will go. The specified file must be writable.
@@ -113,20 +126,23 @@ public void append(LogEvent event) {
* @param append If true will append to fileName. Otherwise will truncate fileName.
*/
private void setFile(boolean append, boolean onlyWhenNull) throws IOException {
- synchronized (token) {
- if (onlyWhenNull && writer != null) return;
- closeFile();
- Resource parent = res.getParentResource();
- if (!parent.exists()) parent.createDirectory(true);
- boolean writeHeader = !append || res.length() == 0;// this must happen before we open the stream
- size = res.length();
- writer = new OutputStreamWriter(new RetireOutputStream(res, append, timeout, listener), charset);
- if (writeHeader) {
- String header = new String(getLayout().getHeader(), charset);
- size += header.length();
- writer.write(header);
- writer.flush();
- // TODO new line?
+ if (!onlyWhenNull || writer == null) {
+ synchronized (token) {
+ if (!onlyWhenNull || writer == null) {
+ closeFile();
+ Resource parent = res.getParentResource();
+ if (!parent.exists()) parent.createDirectory(true);
+ boolean writeHeader = !append || res.length() == 0;// this must happen before we open the stream
+ size = res.length();
+ writer = new OutputStreamWriter(new RetireOutputStream(res, append, timeout, listener), charset);
+ if (writeHeader) {
+ String header = new String(getLayout().getHeader(), charset);
+ size += header.length();
+ writer.write(header);
+ writer.flush();
+ // TODO new line?
+ }
+ }
}
}
}
diff --git a/core/src/main/java/lucee/commons/io/log/log4j2/layout/DataDogLayout.java b/core/src/main/java/lucee/commons/io/log/log4j2/layout/DataDogLayout.java
index d1aaedf58e..7af3841760 100644
--- a/core/src/main/java/lucee/commons/io/log/log4j2/layout/DataDogLayout.java
+++ b/core/src/main/java/lucee/commons/io/log/log4j2/layout/DataDogLayout.java
@@ -231,6 +231,12 @@ private static Object[] getCorrelationIdentifier() {
return ids = new Object[] { "-1", "-1" };
}
+ public static Object[] getCorrelationIdentifierWhenValid() {
+ Object[] _ids = getCorrelationIdentifier();
+ if (idsValid) return _ids;
+ return null;
+ }
+
public int getLineNumber() {
int line = 0;
String template;
diff --git a/core/src/main/java/lucee/commons/io/log/log4j2/layout/JsonLayout.java b/core/src/main/java/lucee/commons/io/log/log4j2/layout/JsonLayout.java
new file mode 100644
index 0000000000..676c9275f3
--- /dev/null
+++ b/core/src/main/java/lucee/commons/io/log/log4j2/layout/JsonLayout.java
@@ -0,0 +1,396 @@
+/**
+ *
+ * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ *
+ **/
+package lucee.commons.io.log.log4j2.layout;
+
+import java.nio.charset.Charset;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.ThreadContext.ContextStack;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.layout.AbstractStringLayout;
+import org.apache.logging.log4j.core.time.Instant;
+import org.apache.logging.log4j.message.Message;
+import org.apache.logging.log4j.message.MultiformatMessage;
+
+import lucee.commons.io.SystemUtil;
+import lucee.commons.lang.ExceptionUtil;
+import lucee.commons.lang.StringUtil;
+import lucee.loader.engine.CFMLEngineFactory;
+import lucee.loader.util.Util;
+import lucee.runtime.PageContext;
+import lucee.runtime.PageContextImpl;
+import lucee.runtime.converter.ConverterException;
+import lucee.runtime.converter.JSONConverter;
+import lucee.runtime.converter.JSONDateFormat;
+import lucee.runtime.engine.ThreadLocalPageContext;
+import lucee.runtime.exp.PageException;
+import lucee.runtime.interpreter.JSONExpressionInterpreter;
+import lucee.runtime.op.Caster;
+import lucee.runtime.security.Credential;
+import lucee.runtime.type.Array;
+import lucee.runtime.type.Struct;
+import lucee.runtime.type.StructImpl;
+import lucee.runtime.util.Creation;
+
+public class JsonLayout extends AbstractStringLayout { // TODO
+
+ private static final int DEFAULT_SIZE = 256;
+ private static final String[] FORMATS = new String[] { "json" };
+ private static final String NL = SystemUtil.getOSSpecificLineSeparator();
+
+ private final boolean includeStacktrace;
+ private final boolean includeTimeMillis;
+ private final boolean stacktraceAsString;
+ private final boolean locationInfo;
+ private final boolean properties;
+ private boolean doComma = true;
+ private final Charset charset;
+ private boolean compact;
+ private boolean hasEnvLoaded;
+ private Object token = new Object();
+ private StructImpl envs;
+ private boolean complete;
+ private String[] envNames;
+
+ // private static final DateFormat dateFormat = new DateFormat(Locale.US);
+ // private static final TimeFormat timeFormat = new TimeFormat(Locale.US);
+
+ public JsonLayout(Charset charset, boolean complete, boolean compact, boolean includeStacktrace, boolean includeTimeMillis, boolean stacktraceAsString, boolean locationInfo,
+ boolean properties, String[] envNames) {
+ super(charset, createHeader(charset, complete), createFooter(charset, complete));
+
+ this.charset = charset;
+ this.includeStacktrace = includeStacktrace;
+ this.includeTimeMillis = includeTimeMillis;
+ this.stacktraceAsString = stacktraceAsString;
+ this.locationInfo = locationInfo;
+ this.properties = properties;
+ this.compact = compact;
+ this.complete = complete;
+ this.envNames = envNames;
+
+ }
+
+ @Override
+ public byte[] getHeader() {
+ doComma = false;
+ return super.getHeader();
+
+ }
+
+ private static byte[] createHeader(Charset cs, boolean complete) {
+ if (!complete) return new byte[] {};
+ return "[".getBytes(cs);
+ }
+
+ private static byte[] createFooter(Charset cs, boolean complete) {
+ if (!complete) return new byte[] {};
+ return "]".getBytes(cs);
+ }
+
+ @Override
+ public String getContentType() {
+ return "application/json; charset=" + this.getCharset();
+ }
+
+ @Override
+ public Map getContentFormat() {
+ final Map result = new HashMap<>();
+ result.put("version", "2.0");
+ return result;
+ }
+
+ @Override
+ public String toSerializable(final LogEvent event) {
+ Creation util = CFMLEngineFactory.getInstance().getCreationUtil();
+ try {
+ Struct root = util.createStruct("linked");
+ long now = event.getTimeMillis();
+ // timeMillis
+ if (includeTimeMillis) {
+ root.setEL("timeMillis", now);
+ }
+ // instant
+ else {
+ Instant instant = event.getInstant();
+ Struct sct = util.createStruct("linked");
+ root.setEL("instant", sct);
+ sct.set("epochSecond", instant.getEpochSecond());
+ sct.set("nanoOfSecond", instant.getNanoOfSecond());
+ }
+
+ root.setEL("thread", event.getThreadName());
+ root.setEL("level", event.getLevel().name());
+
+ // name
+ String name = event.getLoggerName();
+ if (Util.isEmpty(name)) {
+ name = "root";
+ }
+ root.setEL("loggerName", name);
+
+ // marker
+ Marker marker = event.getMarker();
+ if (marker != null) {
+ root.setEL("marker", createMarker(util, marker));
+
+ }
+
+ // Message
+ Message msg = event.getMessage();
+ if (msg != null) {
+ boolean jsonSupported = false;
+ if (msg instanceof MultiformatMessage) {
+ final String[] formats = ((MultiformatMessage) msg).getFormats();
+ for (final String format: formats) {
+ if (format.equalsIgnoreCase("JSON")) {
+ jsonSupported = true;
+ break;
+ }
+ }
+ }
+ // extract message
+ String strMSG;
+ if (jsonSupported) {
+ strMSG = ((MultiformatMessage) msg).getFormattedMessage(FORMATS);
+ }
+ else {
+ strMSG = msg.getFormattedMessage();
+ }
+ if (strMSG == null) strMSG = "";
+
+ // split application name
+ int index = strMSG.indexOf("->");
+ String application;
+ if (index > -1) {
+ application = strMSG.substring(0, index);
+ strMSG = strMSG.substring(index + 2);
+ }
+ else application = "";
+ root.setEL("application", application);
+ root.setEL("message", toJson(strMSG, strMSG));
+ }
+
+ // Thrown
+ Throwable thrown = event.getThrown();
+ if (thrown != null) {
+ Struct sct = util.createStruct("linked");
+ root.setEL("thrown", sct);
+ sct.setEL("commonElementCount", 0D); // TODO
+ sct.setEL("message", thrown.getMessage());
+ sct.setEL("name", thrown.getClass().getName());
+ if (includeStacktrace) {
+ root.setEL("extendedStackTrace", createStacktrace(util, thrown.getStackTrace(), stacktraceAsString));
+ }
+ }
+
+ // context stack
+ {
+ Array contextStack = util.createArray();
+ ContextStack stack = event.getContextStack();
+ if (stack.getDepth() > 0) {
+ for (String cse: stack.asList()) {
+ contextStack.append(cse);
+ }
+
+ }
+ if (contextStack.size() > 0) root.setEL("contextStack", contextStack);
+ }
+ // end of batch
+ root.setEL("endOfBatch", event.isEndOfBatch());
+
+ // TODO "loggerFqcn" : "org.apache.logging.log4j.spi.AbstractLogger",
+
+ // context map
+ if (this.properties) {
+ Map map = event.getContextMap();
+ if (map.size() > 0) {
+ Struct contextMap = util.createStruct("linked");
+ root.setEL("contextMap", contextMap);
+ for (Entry e: map.entrySet()) {
+ contextMap.setEL(e.getKey(), e.getValue());
+ }
+ }
+ }
+
+ // thread
+ {
+ Thread thread = Thread.currentThread();
+ Struct th = util.createStruct("linked");
+ th.setEL("id", thread.getId());
+ th.setEL("priority", thread.getPriority());
+ root.setEL("thread", th);
+ }
+
+ if (this.locationInfo) {
+ StackTraceElement data = null;
+ for (StackTraceElement ste: Thread.currentThread().getStackTrace()) {
+ if (ste.getClassName().startsWith("lucee.commons.io.log.")) continue;
+ if (ste.getClassName().startsWith("org.apache.logging.log4j.")) continue;
+ if (ste.getClassName().equals("lucee.runtime.tag.Log")) continue;
+ data = ste;
+ }
+ if (data != null) {
+ Struct source = util.createStruct("linked");
+ root.setEL("source", source);
+ source.setEL("class", data.getClassName());
+ source.setEL("method", data.getMethodName());
+ source.setEL("file", data.getFileName());
+ source.setEL("line", data.getLineNumber());
+ }
+ }
+ // datadog
+ Object[] ddids = DataDogLayout.getCorrelationIdentifierWhenValid();
+ if (ddids != null && ddids.length == 2) {
+ Struct ids = util.createStruct("linked");
+ ids.set("trace_id", ddids[0]);
+ ids.set("span_id", ddids[1]);
+ root.setEL("dd", ids);
+ }
+
+ // auth user
+ PageContext pc = ThreadLocalPageContext.get();
+ if (pc != null) {
+ String user = null;
+ Credential remoteUser = pc.getRemoteUser();
+ if (remoteUser == null) {
+ user = pc.getHttpServletRequest().getRemoteUser();
+ }
+ else user = remoteUser.getUsername();
+ if (!Util.isEmpty(user, true)) root.setEL("authUser", user);
+
+ root.setEL("pageContextId", pc.getId());
+ if (pc instanceof PageContextImpl) {
+ root.setEL("requestId", ((PageContextImpl) pc).getRequestId());
+ }
+ }
+
+ // env var
+ if (envNames != null && !hasEnvLoaded) {
+ synchronized (token) {
+ if (!hasEnvLoaded) {
+ envs = new StructImpl();
+ for (String v: envNames) {
+ if (!StringUtil.isEmpty(v, true)) {
+ if (!StringUtil.isEmpty(v, true)) {
+ envs.setEL(v, SystemUtil.getSystemPropOrEnvVar(v.trim(), null));
+ }
+ }
+ }
+ hasEnvLoaded = true;
+ }
+ }
+ }
+ if (envs != null && !envs.isEmpty()) {
+ root.setEL("environment", envs);
+ }
+
+ // Properties
+ /*
+ * if (this.properties && event.getContextMap().size() > 0) { Array arr = util.createArray();
+ * sct.setEL("Properties", arr);
+ *
+ * Set> entrySet = event.getContextMap().entrySet(); int i = 1; for (final
+ * Map.Entry entry: entrySet) { Struct s = util.createStruct("linked");
+ * arr.appendEL(s); sct.setEL("name", entry.getKey()); sct.setEL("value", entry.getValue()); } }
+ */
+
+ try {
+ JSONConverter json = new JSONConverter(true, charset, JSONDateFormat.PATTERN_ISO8601, compact, null);
+
+ String result = json.serialize(null, root, -1, Boolean.TRUE);
+ if (doComma) {
+ if (complete) return "," + NL + result;
+ return NL + result;
+ }
+ else doComma = true;
+ return result;
+ }
+ catch (ConverterException e) {
+ throw Caster.toPageException(e);
+ }
+
+ }
+ catch (PageException e) {
+ throw Caster.toPageRuntimeException(e);
+ }
+
+ }
+
+ private static Object toJson(String strJson, Object defaultValue) {
+ if (StringUtil.isEmpty(strJson, true)) {
+ return defaultValue;
+ }
+ strJson = strJson.trim();
+ if ((!strJson.startsWith("{") && !strJson.startsWith("[")) || (!strJson.endsWith("}") && !strJson.endsWith("]"))) {
+ return defaultValue;
+ }
+
+ try {
+ return new JSONExpressionInterpreter().interpret(ThreadLocalPageContext.get(), strJson);
+ }
+ catch (PageException e) {
+ return defaultValue;
+ }
+ }
+
+ private Object createStacktrace(Creation util, StackTraceElement[] stackTraces, boolean stacktraceAsString) throws PageException {
+
+ // Stacktrace
+ //
+ if (stacktraceAsString) {
+ return ExceptionUtil.toString(stackTraces);
+ }
+ else {
+ Array arr = util.createArray();
+ Struct sct;
+ for (StackTraceElement ste: stackTraces) {
+ sct = util.createStruct("linked");
+ arr.appendEL(sct);
+ sct.setEL("class", ste.getClassName());
+ sct.setEL("method", ste.getMethodName());
+ sct.setEL("class", ste.getClassName());
+ sct.setEL("file", ste.getFileName());
+ sct.setEL("line", ste.getLineNumber());
+ sct.setEL("exact", Boolean.TRUE);
+ sct.setEL("location", "classes/");
+ sct.setEL("version", "?");
+ // TODO exact location version
+ }
+ return arr;
+ }
+ }
+
+ private Struct createMarker(Creation util, Marker marker) throws PageException {
+ Struct sct = util.createStruct("linked");
+ sct.setEL("name", marker.getName());
+ Marker[] parents = marker.getParents();
+ if (parents != null && parents.length > 0) {
+ Array arr = util.createArray();
+ sct.setEL("parents", arr);
+ for (Marker p: parents) {
+ arr.appendEL(createMarker(util, p));
+ }
+ }
+ return sct;
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/java/lucee/commons/io/res/ResourceProviderPro.java b/core/src/main/java/lucee/commons/io/res/ResourceProviderPro.java
index 38d5a35de6..2237b1fb4d 100644
--- a/core/src/main/java/lucee/commons/io/res/ResourceProviderPro.java
+++ b/core/src/main/java/lucee/commons/io/res/ResourceProviderPro.java
@@ -22,4 +22,6 @@ public interface ResourceProviderPro extends ResourceProvider {
public char getSeparator();
+ public boolean allowMatching();
+
}
\ No newline at end of file
diff --git a/core/src/main/java/lucee/commons/io/res/ResourcesImpl.java b/core/src/main/java/lucee/commons/io/res/ResourcesImpl.java
index d37764a2f7..e704b4adfa 100755
--- a/core/src/main/java/lucee/commons/io/res/ResourcesImpl.java
+++ b/core/src/main/java/lucee/commons/io/res/ResourcesImpl.java
@@ -18,6 +18,7 @@
*/
package lucee.commons.io.res;
+import java.io.IOException;
import java.util.Map;
import lucee.commons.io.res.type.file.FileResourceProvider;
@@ -163,16 +164,40 @@ public Resource getResource(String path) {
int index = path.indexOf("://");
if (index != -1) {
String scheme = path.substring(0, index).toLowerCase().trim();
- String subPath = path.substring(index + 3);
- for (int i = 0; i < resources.length; i++) {
- if (scheme.equalsIgnoreCase(resources[i].getScheme())) {
- return resources[i].instance().getResource(subPath);
+ if (onlyAlphaNumeric(scheme)) {
+ String subPath = path.substring(index + 3);
+ for (int i = 0; i < resources.length; i++) {
+ if (scheme.equalsIgnoreCase(resources[i].getScheme())) {
+ return resources[i].instance().getResource(subPath);
+ }
+ }
+
+ // create exception
+ StringBuilder sb = new StringBuilder();
+ for (ResourceProviderFactory rpf: resources) {
+ if (sb.length() > 0) sb.append(", ");
+ sb.append(rpf.instance().getScheme());
}
+ throw new PageRuntimeException(
+ new IOException("there is no Resource provider available with the name [" + scheme + "], available resource providers are [" + sb + "]"));
}
}
return defaultResource.getResource(path);
}
+ public static boolean onlyAlphaNumeric(String str) {
+ if (StringUtil.isEmpty(str, true)) return false;
+ str = str.trim();
+ char c;
+ for (int i = str.length() - 1; i >= 0; i--) {
+ c = str.charAt(i);
+ if (!((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
public String getScheme() {
// TODO Auto-generated method stub
return null;
diff --git a/core/src/main/java/lucee/commons/io/res/type/cache/CacheResourceProvider.java b/core/src/main/java/lucee/commons/io/res/type/cache/CacheResourceProvider.java
index 363a716193..353f08ede9 100644
--- a/core/src/main/java/lucee/commons/io/res/type/cache/CacheResourceProvider.java
+++ b/core/src/main/java/lucee/commons/io/res/type/cache/CacheResourceProvider.java
@@ -241,4 +241,9 @@ public char getSeparator() {
return '/';
}
+ @Override
+ public boolean allowMatching() {
+ return false;
+ }
+
}
\ No newline at end of file
diff --git a/core/src/main/java/lucee/commons/io/res/type/cfml/CFMLResourceProvider.java b/core/src/main/java/lucee/commons/io/res/type/cfml/CFMLResourceProvider.java
index 0765d7598c..ef577a7c9d 100644
--- a/core/src/main/java/lucee/commons/io/res/type/cfml/CFMLResourceProvider.java
+++ b/core/src/main/java/lucee/commons/io/res/type/cfml/CFMLResourceProvider.java
@@ -285,4 +285,14 @@ public char getSeparator() {
return '/';
}
+ @Override
+ public boolean allowMatching() {
+ try {
+ return callboolean(null, null, "allowMatching", ZERO_ARGS);
+ }
+ catch (Throwable t) {
+ ExceptionUtil.rethrowIfNecessary(t);
+ return true;
+ }
+ }
}
\ No newline at end of file
diff --git a/core/src/main/java/lucee/commons/io/res/type/datasource/DatasourceResourceProvider.java b/core/src/main/java/lucee/commons/io/res/type/datasource/DatasourceResourceProvider.java
index 12c7e8d78f..a07e0f5078 100755
--- a/core/src/main/java/lucee/commons/io/res/type/datasource/DatasourceResourceProvider.java
+++ b/core/src/main/java/lucee/commons/io/res/type/datasource/DatasourceResourceProvider.java
@@ -572,4 +572,9 @@ public char getSeparator() {
return '/';
}
+ @Override
+ public boolean allowMatching() {
+ return false;
+ }
+
}
\ No newline at end of file
diff --git a/core/src/main/java/lucee/commons/io/res/type/file/FileResource.java b/core/src/main/java/lucee/commons/io/res/type/file/FileResource.java
index fa4700bfd1..603c8858c8 100644
--- a/core/src/main/java/lucee/commons/io/res/type/file/FileResource.java
+++ b/core/src/main/java/lucee/commons/io/res/type/file/FileResource.java
@@ -27,6 +27,8 @@
import java.io.OutputStream;
import java.nio.file.CopyOption;
import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
import java.nio.file.attribute.DosFileAttributes;
@@ -239,10 +241,12 @@ public InputStream getInputStream() throws IOException {
// provider.lock(this);
provider.read(this);
try {
-
return new BufferedInputStream(Files.newInputStream(toPath(), StandardOpenOption.READ));
// return new BufferedInputStream(new FileInputStream(this));
}
+ catch (NoSuchFileException nsfe) {
+ throw ExceptionUtil.toFileNotFoundException(nsfe);
+ }
catch (IOException ioe) {
// provider.unlock(this);
throw ioe;
@@ -275,12 +279,9 @@ public void createFile(boolean createParentWhenNotExists) throws IOException {
try {
if (createParentWhenNotExists) {
File p = super.getParentFile();
- if (!p.exists()) p.mkdirs();
- }
- if (!super.createNewFile()) {
- if (super.isFile()) throw new IOException("Can't create file [" + this + "], file already exists");
- throw new IOException("Can't create file [" + this + "]");
+ if (!p.exists()) Files.createDirectories(p.toPath());
}
+ Files.createFile(toPath());
}
finally {
provider.unlock(this);
@@ -338,10 +339,8 @@ public ContentType getContentType() {
public void createDirectory(boolean createParentWhenNotExists) throws IOException {
provider.lock(this);
try {
- if (createParentWhenNotExists ? !_mkdirs() : !super.mkdir()) {
- if (super.isDirectory()) throw new IOException("Can't create directory [" + this + "], directory already exists");
- throw new IOException("Can't create directory [" + this + "]");
- }
+ if (createParentWhenNotExists) Files.createDirectories(toPath());
+ else Files.createDirectory(toPath());
}
finally {
provider.unlock(this);
@@ -408,6 +407,29 @@ public int getMode() {
return mode;
}
+ public static int getMode(Path path) {
+ if (!Files.exists(path)) return 0;
+ if (SystemUtil.isUnix()) {
+ try {
+ // TODO geht nur fuer file
+ String line = Command.execute("ls -ld " + path.toAbsolutePath().toString(), false).getOutput();
+
+ line = line.trim();
+ line = line.substring(0, line.indexOf(' '));
+ // print.ln(getPath());
+ return ModeUtil.toOctalMode(line);
+
+ }
+ catch (Exception e) {
+ }
+
+ }
+ int mode = SystemUtil.isWindows() ? 0111 : 0;
+ if (Files.isReadable(path)) mode += 0444;
+ if (Files.isWritable(path)) mode += 0222;
+ return mode;
+ }
+
@Override
public void setMode(int mode) throws IOException {
// TODO unter windows mit setReadable usw.
diff --git a/core/src/main/java/lucee/commons/io/res/type/file/FileResourceProvider.java b/core/src/main/java/lucee/commons/io/res/type/file/FileResourceProvider.java
index aabc17d1bb..b90271126b 100644
--- a/core/src/main/java/lucee/commons/io/res/type/file/FileResourceProvider.java
+++ b/core/src/main/java/lucee/commons/io/res/type/file/FileResourceProvider.java
@@ -117,4 +117,9 @@ public Map getArguments() {
public char getSeparator() {
return File.separatorChar;
}
+
+ @Override
+ public boolean allowMatching() {
+ return true;
+ }
}
\ No newline at end of file
diff --git a/core/src/main/java/lucee/commons/io/res/type/ftp/FTPResourceProvider.java b/core/src/main/java/lucee/commons/io/res/type/ftp/FTPResourceProvider.java
index a3b7089804..a1ffa0dd42 100644
--- a/core/src/main/java/lucee/commons/io/res/type/ftp/FTPResourceProvider.java
+++ b/core/src/main/java/lucee/commons/io/res/type/ftp/FTPResourceProvider.java
@@ -256,4 +256,9 @@ public char getSeparator() {
return '/';
}
+ @Override
+ public boolean allowMatching() {
+ return false;
+ }
+
}
\ No newline at end of file
diff --git a/core/src/main/java/lucee/commons/io/res/type/http/HTTPResource.java b/core/src/main/java/lucee/commons/io/res/type/http/HTTPResource.java
index 27f7e238c1..f9b4c513ac 100755
--- a/core/src/main/java/lucee/commons/io/res/type/http/HTTPResource.java
+++ b/core/src/main/java/lucee/commons/io/res/type/http/HTTPResource.java
@@ -21,6 +21,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
+import java.security.GeneralSecurityException;
import lucee.commons.io.IOUtil;
import lucee.commons.io.res.ContentType;
@@ -28,10 +29,12 @@
import lucee.commons.io.res.ResourceProvider;
import lucee.commons.io.res.util.ReadOnlyResourceSupport;
import lucee.commons.io.res.util.ResourceUtil;
+import lucee.commons.lang.ExceptionUtil;
import lucee.commons.lang.StringUtil;
import lucee.commons.net.http.HTTPEngine;
import lucee.commons.net.http.HTTPResponse;
import lucee.commons.net.http.Header;
+import lucee.commons.net.http.httpclient.HTTPEngine4Impl;
import lucee.runtime.net.proxy.ProxyData;
import lucee.runtime.net.proxy.ProxyDataImpl;
import lucee.runtime.op.Caster;
@@ -54,32 +57,32 @@ public HTTPResource(HTTPResourceProvider provider, HTTPConnectionData data) {
}
- private HTTPResponse getHTTPResponse(boolean create) throws IOException {
+ private HTTPResponse getHTTPResponse(boolean create) throws IOException, GeneralSecurityException {
if (create || http == null) {
// URL url = HTTPUtil.toURL("http://"+data.host+":"+data.port+"/"+data.path);
URL url = new URL(provider.getProtocol(), data.host, data.port, data.path);
// TODO Support for proxy
ProxyData pd = ProxyDataImpl.isValid(data.proxyData, url.getHost()) ? data.proxyData : ProxyDataImpl.NO_PROXY;
- http = HTTPEngine.get(url, data.username, data.password, _getTimeout(), true, null, data.userAgent, pd, null);
+ http = HTTPEngine4Impl.get(url, data.username, data.password, _getTimeout(), true, null, data.userAgent, pd, null);
}
return http;
}
- private int getStatusCode() throws IOException {
+ private int getStatusCode() throws IOException, GeneralSecurityException {
if (http == null) {
URL url = new URL(provider.getProtocol(), data.host, data.port, data.path);
ProxyData pd = ProxyDataImpl.isValid(data.proxyData, url.getHost()) ? data.proxyData : ProxyDataImpl.NO_PROXY;
- return HTTPEngine.head(url, data.username, data.password, _getTimeout(), true, null, data.userAgent, pd, null).getStatusCode();
+ return HTTPEngine4Impl.head(url, data.username, data.password, _getTimeout(), true, null, data.userAgent, pd, null).getStatusCode();
}
return http.getStatusCode();
}
- public ContentType getContentType() throws IOException {
+ public ContentType getContentType() throws IOException, GeneralSecurityException {
if (http == null) {
URL url = new URL(provider.getProtocol(), data.host, data.port, data.path);
ProxyData pd = ProxyDataImpl.isValid(data.proxyData, url.getHost()) ? data.proxyData : ProxyDataImpl.NO_PROXY;
- return HTTPEngine.head(url, data.username, data.password, _getTimeout(), true, null, data.userAgent, pd, null).getContentType();
+ return HTTPEngine4Impl.head(url, data.username, data.password, _getTimeout(), true, null, data.userAgent, pd, null).getContentType();
}
return http.getContentType();
}
@@ -91,7 +94,7 @@ public boolean exists() {
int code = getStatusCode();// getHttpMethod().getStatusCode();
return code != 404;
}
- catch (IOException e) {
+ catch (Exception e) {
return false;
}
}
@@ -102,7 +105,7 @@ public int statusCode() {
provider.read(this);
return (rsp = getHTTPResponse(false)).getStatusCode();
}
- catch (IOException e) {
+ catch (Exception e) {
return 0;
}
finally {
@@ -115,13 +118,15 @@ public InputStream getInputStream() throws IOException {
// ResourceUtil.checkGetInputStreamOK(this);
// provider.lock(this);
provider.read(this);
- HTTPResponse method = getHTTPResponse(true);
+ HTTPResponse method;
try {
- return IOUtil.toBufferedInputStream(method.getContentAsStream());
+ method = getHTTPResponse(true);
+ }
+ catch (GeneralSecurityException e) {
+ throw ExceptionUtil.toIOException(e);
}
- catch (IOException e) {
- // provider.unlock(this);
- throw e;
+ try {
+ return IOUtil.toBufferedInputStream(method.getContentAsStream());
}
finally {
HTTPEngine.closeEL(method);
@@ -194,7 +199,7 @@ public long lastModified() {
Header cl = (rsp = getHTTPResponse(false)).getLastHeaderIgnoreCase("last-modified");
if (cl != null && exists()) last = Caster.toIntValue(cl.getValue(), 0);
}
- catch (IOException e) {
+ catch (Exception e) {
}
finally {
HTTPEngine.closeEL(rsp);
@@ -209,7 +214,7 @@ public long length() {
if (!exists()) return 0;
return (rsp = getHTTPResponse(false)).getContentLength();
}
- catch (IOException e) {
+ catch (Exception e) {
return 0;
}
finally {
diff --git a/core/src/main/java/lucee/commons/io/res/type/http/HTTPResourceProvider.java b/core/src/main/java/lucee/commons/io/res/type/http/HTTPResourceProvider.java
index cf010c1ef2..ab7abdd3f8 100644
--- a/core/src/main/java/lucee/commons/io/res/type/http/HTTPResourceProvider.java
+++ b/core/src/main/java/lucee/commons/io/res/type/http/HTTPResourceProvider.java
@@ -158,4 +158,9 @@ public Map getArguments() {
public char getSeparator() {
return '/';
}
+
+ @Override
+ public boolean allowMatching() {
+ return false;
+ }
}
\ No newline at end of file
diff --git a/core/src/main/java/lucee/commons/io/res/type/ram/RamResourceProviderOld.java b/core/src/main/java/lucee/commons/io/res/type/ram/RamResourceProviderOld.java
index 0211846bc8..a92e79f4eb 100755
--- a/core/src/main/java/lucee/commons/io/res/type/ram/RamResourceProviderOld.java
+++ b/core/src/main/java/lucee/commons/io/res/type/ram/RamResourceProviderOld.java
@@ -167,4 +167,9 @@ public Map getArguments() {
public char getSeparator() {
return '/';
}
+
+ @Override
+ public boolean allowMatching() {
+ return false;
+ }
}
\ No newline at end of file
diff --git a/core/src/main/java/lucee/commons/io/res/type/s3/DummyS3ResourceProvider.java b/core/src/main/java/lucee/commons/io/res/type/s3/DummyS3ResourceProvider.java
index 028a5b98d3..37277fd26b 100755
--- a/core/src/main/java/lucee/commons/io/res/type/s3/DummyS3ResourceProvider.java
+++ b/core/src/main/java/lucee/commons/io/res/type/s3/DummyS3ResourceProvider.java
@@ -100,4 +100,9 @@ private PageRuntimeException notInstalledEL() {
return new PageRuntimeException(notInstalled());
}
+ @Override
+ public boolean allowMatching() {
+ throw notInstalledEL();
+ }
+
}
\ No newline at end of file
diff --git a/core/src/main/java/lucee/commons/io/res/type/tar/TarResourceProvider.java b/core/src/main/java/lucee/commons/io/res/type/tar/TarResourceProvider.java
index e6afbba3c6..4cfb5d76d4 100644
--- a/core/src/main/java/lucee/commons/io/res/type/tar/TarResourceProvider.java
+++ b/core/src/main/java/lucee/commons/io/res/type/tar/TarResourceProvider.java
@@ -49,9 +49,14 @@ public boolean isCaseSensitive() {
public boolean isModeSupported() {
return true;
}
-
+
@Override
public char getSeparator() {
return '/';
}
+
+ @Override
+ public boolean allowMatching() {
+ return false;
+ }
}
\ No newline at end of file
diff --git a/core/src/main/java/lucee/commons/io/res/type/tgz/TGZResourceProvider.java b/core/src/main/java/lucee/commons/io/res/type/tgz/TGZResourceProvider.java
index 3783c94067..e1205dae14 100644
--- a/core/src/main/java/lucee/commons/io/res/type/tgz/TGZResourceProvider.java
+++ b/core/src/main/java/lucee/commons/io/res/type/tgz/TGZResourceProvider.java
@@ -54,4 +54,9 @@ public boolean isModeSupported() {
public char getSeparator() {
return '/';
}
+
+ @Override
+ public boolean allowMatching() {
+ return false;
+ }
}
\ No newline at end of file
diff --git a/core/src/main/java/lucee/commons/io/res/type/zip/ZipResourceProvider.java b/core/src/main/java/lucee/commons/io/res/type/zip/ZipResourceProvider.java
index ebe5f0ca48..e235436599 100644
--- a/core/src/main/java/lucee/commons/io/res/type/zip/ZipResourceProvider.java
+++ b/core/src/main/java/lucee/commons/io/res/type/zip/ZipResourceProvider.java
@@ -48,10 +48,15 @@ public boolean isCaseSensitive() {
@Override
public boolean isModeSupported() {
return false;
- }
-
+ }
+
@Override
public char getSeparator() {
return '/';
}
+
+ @Override
+ public boolean allowMatching() {
+ return false;
+ }
}
diff --git a/core/src/main/java/lucee/commons/io/res/util/ExactMatchFilter.java b/core/src/main/java/lucee/commons/io/res/util/ExactMatchFilter.java
new file mode 100644
index 0000000000..4d18238f3e
--- /dev/null
+++ b/core/src/main/java/lucee/commons/io/res/util/ExactMatchFilter.java
@@ -0,0 +1,28 @@
+package lucee.commons.io.res.util;
+import lucee.commons.io.res.Resource;
+import lucee.commons.io.res.ResourceProvider;
+import lucee.commons.io.res.ResourceProviderPro;
+import lucee.commons.io.res.filter.ResourceNameFilter;
+
+public class ExactMatchFilter implements ResourceNameFilter {
+
+ private String name;
+
+ public ExactMatchFilter(String name) {
+ this.name = name == null ? "" : name;
+ }
+
+ @Override
+ public boolean accept(Resource parent, String name) {
+ return this.name.equalsIgnoreCase(name);
+ }
+
+ public static boolean allowMatching(ResourceProvider provider) {
+
+ if (provider instanceof ResourceProviderPro) {
+ return ((ResourceProviderPro) provider).allowMatching();
+ }
+
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/java/lucee/commons/io/res/util/ModeObjectWrap.java b/core/src/main/java/lucee/commons/io/res/util/ModeObjectWrap.java
index 16647f8120..de50ff5c9c 100644
--- a/core/src/main/java/lucee/commons/io/res/util/ModeObjectWrap.java
+++ b/core/src/main/java/lucee/commons/io/res/util/ModeObjectWrap.java
@@ -18,8 +18,11 @@
**/
package lucee.commons.io.res.util;
+import java.nio.file.Path;
+
import lucee.commons.io.ModeUtil;
import lucee.commons.io.res.Resource;
+import lucee.commons.io.res.type.file.FileResource;
import lucee.runtime.engine.ThreadLocalPageContext;
import lucee.runtime.exp.PageException;
import lucee.runtime.op.Castable;
@@ -33,13 +36,18 @@ public final class ModeObjectWrap implements ObjectWrap, Castable {
private static final long serialVersionUID = -1630745501422006978L;
- private final Resource res;
+ private Resource res;
+ private Path path;
private String mode = null;
public ModeObjectWrap(Resource res) {
this.res = res;
}
+ public ModeObjectWrap(Path path) {
+ this.path = path;
+ }
+
@Override
public Object getEmbededObject() {
return toString();
@@ -52,8 +60,14 @@ public Object getEmbededObject(Object def) {
@Override
public String toString() {
- // print.dumpStack();
- if (mode == null) mode = ModeUtil.toStringMode(res.getMode());
+ if (mode == null) {
+ if (res != null) {
+ mode = ModeUtil.toStringMode(res.getMode());
+ }
+ else {
+ mode = ModeUtil.toStringMode(FileResource.getMode(path));
+ }
+ }
return mode;
}
diff --git a/core/src/main/java/lucee/commons/io/res/util/ResourceLockImpl.java b/core/src/main/java/lucee/commons/io/res/util/ResourceLockImpl.java
index 115e3ad285..a1a2e46dd4 100644
--- a/core/src/main/java/lucee/commons/io/res/util/ResourceLockImpl.java
+++ b/core/src/main/java/lucee/commons/io/res/util/ResourceLockImpl.java
@@ -36,7 +36,7 @@
import lucee.runtime.net.http.ReqRspUtil;
public final class ResourceLockImpl implements ResourceLock {
-
+ // MUST LDEV-4568
private static final long serialVersionUID = 6888529579290798651L;
private long lockTimeout;
@@ -52,12 +52,11 @@ public ResourceLockImpl(long timeout, boolean caseSensitive) {
@Override
public void lock(Resource res) {
- String path = getPath(res);
-
- synchronized (token) {
- _read(path);
- resources.put(path, Thread.currentThread());
- }
+ /*
+ * String path = getPath(res);
+ *
+ * synchronized (token) { _read(path); resources.put(path, Thread.currentThread()); }
+ */
}
private String getPath(Resource res) {
@@ -66,21 +65,16 @@ private String getPath(Resource res) {
@Override
public void unlock(Resource res) {
- String path = getPath(res);
- // if(path.endsWith(".dmg"))print.err("unlock:"+path);
- synchronized (token) {
- resources.remove(path);
- token.notifyAll();
- }
+ /*
+ * String path = getPath(res); synchronized (token) { resources.remove(path); token.notifyAll(); }
+ */
}
@Override
public void read(Resource res) {
- String path = getPath(res);
- synchronized (token) {
- // print.ln(".......");
- _read(path);
- }
+ /*
+ * String path = getPath(res); synchronized (token) { _read(path); }
+ */
}
private void _read(String path) {
diff --git a/core/src/main/java/lucee/commons/io/res/util/ResourceProviderWrapper.java b/core/src/main/java/lucee/commons/io/res/util/ResourceProviderWrapper.java
index ed76b45b28..07036b41d0 100755
--- a/core/src/main/java/lucee/commons/io/res/util/ResourceProviderWrapper.java
+++ b/core/src/main/java/lucee/commons/io/res/util/ResourceProviderWrapper.java
@@ -94,4 +94,9 @@ public char getSeparator() {
return ResourceUtil.getSeparator(provider);
}
+ @Override
+ public boolean allowMatching() {
+ return ResourceUtil.allowMatching(provider, false);
+ }
+
}
\ No newline at end of file
diff --git a/core/src/main/java/lucee/commons/io/res/util/ResourceUtil.java b/core/src/main/java/lucee/commons/io/res/util/ResourceUtil.java
index aae301fe7e..b17b11b7a4 100755
--- a/core/src/main/java/lucee/commons/io/res/util/ResourceUtil.java
+++ b/core/src/main/java/lucee/commons/io/res/util/ResourceUtil.java
@@ -22,14 +22,19 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
+import java.lang.reflect.Method;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
import lucee.commons.digest.Hash;
import lucee.commons.io.IOUtil;
import lucee.commons.io.SystemUtil;
+import lucee.commons.io.log.Log;
+import lucee.commons.io.log.LogUtil;
import lucee.commons.io.res.ContentType;
import lucee.commons.io.res.ContentTypeImpl;
import lucee.commons.io.res.Resource;
@@ -41,6 +46,7 @@
import lucee.commons.io.res.filter.IgnoreSystemFiles;
import lucee.commons.io.res.filter.ResourceFilter;
import lucee.commons.io.res.filter.ResourceNameFilter;
+import lucee.commons.io.res.type.file.FileResource;
import lucee.commons.io.res.type.http.HTTPResource;
import lucee.commons.lang.ExceptionUtil;
import lucee.commons.lang.StringUtil;
@@ -50,12 +56,14 @@
import lucee.runtime.PageSourceImpl;
import lucee.runtime.config.Config;
import lucee.runtime.config.ConfigWeb;
+import lucee.runtime.config.ConfigWebPro;
import lucee.runtime.config.ConfigWebUtil;
import lucee.runtime.config.Constants;
import lucee.runtime.engine.ThreadLocalPageContext;
import lucee.runtime.exp.ExpressionException;
import lucee.runtime.exp.PageException;
import lucee.runtime.functions.system.ExpandPath;
+import lucee.runtime.op.Caster;
import lucee.runtime.type.util.ArrayUtil;
import lucee.runtime.type.util.ListUtil;
@@ -95,8 +103,10 @@ public final class ResourceUtil {
* Field LEVEL_GRAND_PARENT_FILE
*/
public static final short LEVEL_GRAND_PARENT_FILE = 2;
+ public static final short LEVEL_ALL = 4;
public static final HashMap EXT_MT = new HashMap();
+ private static Map allowMatchings = new ConcurrentHashMap<>();
static {
EXT_MT.put("ai", "application/postscript");
EXT_MT.put("aif", "audio/x-aiff");
@@ -207,7 +217,7 @@ public static Resource toResourceExisting(PageContext pc, String path, boolean a
Resource res = pc.getConfig().getResource(path);
if (res.exists()) return res;
- else if (!allowRealpath) throw new ExpressionException("file or directory [" + StringUtil.max(path, 255, "...") + "] does not exist");
+ else if (!allowRealpath) throw new ExpressionException("file or directory [" + StringUtil.max(path, 255, "...") + "] does not exist");
if (res.isAbsolute() && res.exists()) {
return res;
@@ -215,18 +225,19 @@ public static Resource toResourceExisting(PageContext pc, String path, boolean a
if (StringUtil.startsWith(path, '/')) {
PageContextImpl pci = (PageContextImpl) pc;
ConfigWeb cw = pc.getConfig();
- PageSource[] sources = cw.getPageSources(pci, ExpandPath.mergeMappings(pc.getApplicationContext().getMappings(), pc.getApplicationContext().getComponentMappings()),
- path, false, pci.useSpecialMappings(), true, false);
- if (!ArrayUtil.isEmpty(sources)) {
+ Resource[] sources = ((ConfigWebPro) cw).getResources(pci,
+ ExpandPath.mergeMappings(pc.getApplicationContext().getMappings(), pc.getApplicationContext().getComponentMappings()), path, false, pci.useSpecialMappings(),
+ true, false, false);
+ if (!ArrayUtil.isEmpty(sources)) {
for (int i = 0; i < sources.length; i++) {
- if (sources[i].exists()) return sources[i].getResource();
+ if (sources[i].exists()) return sources[i];
}
}
}
res = getRealResource(pc, path, res);
if (res.exists()) return res;
- throw new ExpressionException("file or directory [" + StringUtil.max(path, 255, "...") + "] does not exist");
+ throw new ExpressionException("file or directory [" + StringUtil.max(path, 255, "...") + "] does not exist");
}
public static Resource toResourceExisting(Config config, String path) throws ExpressionException {
@@ -237,7 +248,7 @@ public static Resource toResourceExisting(Config config, String path) throws Exp
else res = config.getResource(path);
if (res.exists()) return res;
- throw new ExpressionException("file or directory [" + StringUtil.max(path, 255, "...") + "] does not exist");
+ throw new ExpressionException("file or directory [" + StringUtil.max(path, 255, "...") + "] does not exist");
}
public static Resource toResourceExisting(Config config, String path, Resource defaultValue) {
@@ -246,7 +257,6 @@ public static Resource toResourceExisting(Config config, String path, Resource d
Resource res;
if (config == null) res = ResourcesImpl.getFileResourceProvider().getResource(path);
else res = config.getResource(path);
-
if (res.exists()) return res;
return defaultValue;
}
@@ -279,7 +289,7 @@ public static Resource toResourceExistingParent(PageContext pc, String destinati
// not allow realpath
if (!allowRealpath) {
if (res.exists() || parentExists(res)) return res;
- throw new ExpressionException("parent directory [" + res.getParent() + "] for file [" + StringUtil.max(destination, 255, "...") + "] doesn't exist");
+ throw new ExpressionException("parent directory [" + res.getParent() + "] for file [" + StringUtil.max(destination, 255, "...") + "] doesn't exist");
}
@@ -291,12 +301,15 @@ public static Resource toResourceExistingParent(PageContext pc, String destinati
if (StringUtil.startsWith(destination, '/')) {
PageContextImpl pci = (PageContextImpl) pc;
ConfigWeb cw = pc.getConfig();
- PageSource[] sources = cw.getPageSources(pci, ExpandPath.mergeMappings(pc.getApplicationContext().getMappings(), pc.getApplicationContext().getComponentMappings()),
- destination, false, pci.useSpecialMappings(), true);
+
+ Resource[] sources = ((ConfigWebPro) cw).getResources(pci,
+ ExpandPath.mergeMappings(pc.getApplicationContext().getMappings(), pc.getApplicationContext().getComponentMappings()), destination, false,
+ pci.useSpecialMappings(), false, true, false);
+
if (!ArrayUtil.isEmpty(sources)) {
for (int i = 0; i < sources.length; i++) {
if (sources[i].exists() || parentExists(sources[i])) {
- res = sources[i].getResource();
+ res = sources[i];
if (res != null) return res;
}
}
@@ -305,7 +318,7 @@ public static Resource toResourceExistingParent(PageContext pc, String destinati
res = getRealResource(pc, destination, res);
if (res != null && (res.exists() || parentExists(res))) return res;
- throw new ExpressionException("parent directory [" + res.getParent() + "] for file [" + StringUtil.max(destination, 255, "...") + "] doesn't exist");
+ throw new ExpressionException("parent directory [" + res.getParent() + "] for file [" + StringUtil.max(destination, 255, "...") + "] doesn't exist");
}
@@ -336,11 +349,12 @@ public static Resource toResourceNotExisting(PageContext pc, String destination,
if (!(isUNC = isUNCPath(destination)) && StringUtil.startsWith(destination, '/')) {
PageContextImpl pci = (PageContextImpl) pc;
ConfigWeb cw = pc.getConfig();
- PageSource[] sources = cw.getPageSources(pci, ExpandPath.mergeMappings(pc.getApplicationContext().getMappings(), pc.getApplicationContext().getComponentMappings()),
- destination, false, pci.useSpecialMappings(), SystemUtil.isWindows(), checkComponentMappings);
+ Resource[] sources = ((ConfigWebPro) cw).getResources(pci,
+ ExpandPath.mergeMappings(pc.getApplicationContext().getMappings(), pc.getApplicationContext().getComponentMappings()), destination, false,
+ pci.useSpecialMappings(), SystemUtil.isWindows(), checkComponentMappings, false);
if (!ArrayUtil.isEmpty(sources)) {
for (int i = 0; i < sources.length; i++) {
- res = sources[i].getResource();
+ res = sources[i];
if (res != null) return res;
}
}
@@ -357,13 +371,21 @@ public static Resource toResourceNotExisting(PageContext pc, String destination,
}
private static Resource getRealResource(PageContext pc, String destination, Resource defaultValue) {
- PageSource ps = pc.getCurrentPageSource();
+ PageSource ps = pc.getCurrentPageSource(null);
if (ps != null) {
- ps = ps.getRealPage(destination);
+ if (ps instanceof PageSourceImpl) {
+ Resource res = ((PageSourceImpl) ps).getRealResource(destination);
+ if (res != null) return res;
+ }
+ // we should no longer come ever to this point
+ LogUtil.log(Log.LEVEL_ERROR, "resources", "expected PageSoucre to be from type PageSourceImpl, but it is not, it is [" + ps.getClass().getName() + "]");
+ ps = ps.getRealPage(destination);
if (ps != null) {
Resource res = ps.getResource();
- if (res != null) return getCanonicalResourceEL(res);
+ if (res != null) {
+ return getCanonicalResourceEL(res);
+ }
}
}
@@ -394,14 +416,18 @@ public static boolean isWindowsPath(String path) {
*/
public static Resource toExactResource(Resource res) {
res = getCanonicalResourceEL(res);
- if (res.getResourceProvider().isCaseSensitive()) {
+ if (res.getResourceProvider().isCaseSensitive() && toResourceProviderPro(res.getResourceProvider()).allowMatching()) {
if (res.exists()) return res;
return _check(res);
-
}
return res;
}
+ private static ResourceProviderPro toResourceProviderPro(ResourceProvider provider) {
+ if (provider instanceof ResourceProviderPro) return (ResourceProviderPro) provider;
+ return new ResourceProviderWrapper(provider);
+ }
+
private static Resource _check(Resource file) {
// todo cascade durch while ersetzten
Resource parent = file.getParentResource();
@@ -413,12 +439,11 @@ private static Resource _check(Resource file) {
if (op == parent) return file;
if ((file = parent.getRealResource(file.getName())).exists()) return file;
}
-
- String[] files = parent.list();
- if (files == null) return file;
- String name = file.getName();
- for (int i = 0; i < files.length; i++) {
- if (name.equalsIgnoreCase(files[i])) return parent.getRealResource(files[i]);
+ // we filter so the VFS Resource must not provide all the entries in the directory
+ String[] names = parent.list(new ExactMatchFilter(file.getName()));
+ if (names == null) return file;
+ for (String name: names) {
+ return parent.getRealResource(name);
}
return file;
}
@@ -432,10 +457,9 @@ private static Resource _check(Resource file) {
* @return file if exists, otherwise null
*/
public static Resource createResource(Resource res, short level, short type) {
-
boolean asDir = type == TYPE_DIR;
// File
- if (level >= LEVEL_FILE && res.exists() && ((res.isDirectory() && asDir) || (res.isFile() && !asDir))) {
+ if (level >= LEVEL_FILE && ((asDir && res.isDirectory()) || (!asDir && res.isFile()))) {
return getCanonicalResourceEL(res);
}
@@ -463,6 +487,15 @@ public static Resource createResource(Resource res, short level, short type) {
}
}
}
+ // All
+ if (level >= LEVEL_ALL && parent != null) {
+ if (asDir) {
+ if (res.mkdirs()) return getCanonicalResourceEL(res);
+ }
+ else {
+ if (parent.mkdirs() && createNewResourceEL(res)) return getCanonicalResourceEL(res);
+ }
+ }
return null;
}
@@ -728,6 +761,16 @@ public static Resource getCanonicalResourceEL(Resource res) {
}
}
+ public static File getCanonicalFileEL(File file) {
+ if (file == null) return file;
+ try {
+ return file.getCanonicalFile();
+ }
+ catch (IOException e) {
+ return file.getAbsoluteFile();
+ }
+ }
+
/**
* creates a new File
*
@@ -816,9 +859,14 @@ public static String getMimeType(Resource res, String fileName, String defaultVa
* @return is inside or not
*/
public static boolean isChildOf(Resource file, Resource dir) {
- while (file != null) {
- if (file.equals(dir)) return true;
- file = file.getParentResource();
+ if (dir == null || !file.getResourceProvider().getScheme().equals(dir.getResourceProvider().getScheme())) return false;
+ //
+ if ((file.getAbsolutePath()).startsWith(dir.getAbsolutePath())) {
+ return true;
+ }
+
+ if ((getCanonicalPathEL(file)).startsWith(getCanonicalPathEL(dir))) {
+ return true;
}
return false;
}
@@ -829,18 +877,19 @@ public static boolean isChildOf(Resource file, Resource dir) {
* @param file file to search
* @param dir directory to search
*/
- public static String getPathToChild(Resource file, Resource dir) {
+ public static String getPathToChild(Resource file, final Resource dir) {
if (dir == null || !file.getResourceProvider().getScheme().equals(dir.getResourceProvider().getScheme())) return null;
- boolean isFile = file.isFile();
- String str = "/";
- while (file != null) {
- if (file.equals(dir)) {
- if (isFile) return str.substring(0, str.length() - 1);
- return str;
- }
- str = "/" + file.getName() + str;
- file = file.getParentResource();
+
+ String strFile, strDir;
+ //
+ if ((strFile = file.getAbsolutePath()).startsWith(strDir = dir.getAbsolutePath())) {
+ return strFile.substring(strDir.length());
+ }
+
+ if ((strFile = getCanonicalPathEL(file)).startsWith(strDir = getCanonicalPathEL(dir))) {
+ return strFile.substring(strDir.length());
}
+
return null;
}
@@ -1073,7 +1122,7 @@ public static ContentType getContentType(Resource resource) {
try {
return ((HTTPResource) resource).getContentType();
}
- catch (IOException e) {
+ catch (Exception e) {
}
}
InputStream is = null;
@@ -1094,7 +1143,7 @@ public static ContentType getContentType(Resource resource, ContentType defaultV
try {
return ((HTTPResource) resource).getContentType();
}
- catch (IOException e) {
+ catch (Exception e) {
}
}
InputStream is = null;
@@ -1547,4 +1596,70 @@ public static File toFile(Resource res) throws IOException {
throw new IOException("cannot convert [" + res + "] to a local file from type [" + res.getResourceProvider().getScheme() + "]");
}
+ /**
+ * gives you the nearest existing ancestor folder (expect the root) of the given file/directory
+ *
+ * @param res resource to check
+ * @param defaultValue if there is no ancestor it return this
+ */
+ public static Resource getExistingAncestorFolder(Resource res, Resource defaultValue) {
+ if (res == null) return defaultValue;
+ Resource p;
+ while (true) {
+ p = res.getParentResource();
+ if (p == null) break;
+ if (res.exists()) return res;
+ res = p;
+ }
+ return defaultValue;
+ }
+
+ public static boolean doesParentExists(Resource res) {
+ if (res == null) return false;
+ Resource p = res.getParentResource();
+ return p != null && p.isDirectory();
+ }
+
+ public static boolean doesGrandParentExists(Resource res) {
+ if (res == null) return false;
+ Resource p = res.getParentResource();
+ if (p == null) return false;
+ p = res.getParentResource();
+ return p != null && p.isDirectory();
+ }
+
+ public static void deleteOnExit(Resource res) {
+ if (res instanceof FileResource) {
+ ((FileResource) res).deleteOnExit();
+ }
+ }
+
+ public static boolean allowMatching(ResourceProvider provider, boolean defaultValue) {
+ String key = provider.getScheme() + ":" + provider.hashCode();
+ Boolean am = allowMatchings.get(key);
+ if (am == null) {
+ synchronized (SystemUtil.createToken("resources", key)) {
+ am = allowMatchings.get(key);
+ if (am == null) {
+ try {
+ Method m = provider.getClass().getMethod("allowMatching", new Class[] {});
+ boolean res = Caster.toBooleanValue(m.invoke(provider, new Object[] {}), defaultValue);
+ allowMatchings.put(key, res);
+ return res;
+ }
+ catch (Exception e) {
+ allowMatchings.put(key, defaultValue);
+ return defaultValue;
+ }
+ }
+ }
+ }
+ return am;
+ }
+
+ public static void createParentDirectoryIfNecessary(Resource file) throws IOException {
+ Resource parent = file.getParentResource();
+ if (parent == null) throw new IOException("there is no parent directory for [" + file + "]");
+ if (!parent.isDirectory()) parent.createDirectory(true);
+ }
}
diff --git a/core/src/main/java/lucee/commons/io/res/util/UDFFilter.java b/core/src/main/java/lucee/commons/io/res/util/UDFFilter.java
index 6624153950..3c71ff1b1b 100644
--- a/core/src/main/java/lucee/commons/io/res/util/UDFFilter.java
+++ b/core/src/main/java/lucee/commons/io/res/util/UDFFilter.java
@@ -28,7 +28,6 @@
import lucee.runtime.exp.PageRuntimeException;
import lucee.runtime.op.Caster;
import lucee.runtime.type.UDF;
-import lucee.commons.io.res.util.ResourceUtil;
public class UDFFilter extends UDFFilterSupport implements ResourceAndResourceNameFilter {
@@ -52,14 +51,14 @@ public boolean accept(Resource file) {
Object[] args1 = new Object[3];
boolean isDir = file.isDirectory();
args1[0] = file.getAbsolutePath();
- args1[1] = file.isDirectory() ? "directory" : "file";
- args1[2] = file.isDirectory() ? "" : ResourceUtil.getExtension(file, null);
+ args1[1] = file.isDirectory() ? "directory" : "file";
+ args1[2] = file.isDirectory() ? "" : ResourceUtil.getExtension(file, null);
try {
return Caster.toBooleanValue(udf.call(ThreadLocalPageContext.get(), args1, true));
}
catch (PageException e) {
throw new PageRuntimeException(e);
- }
+ }
}
@Override
diff --git a/core/src/main/java/lucee/commons/io/res/util/UDFFilterSupport.java b/core/src/main/java/lucee/commons/io/res/util/UDFFilterSupport.java
index b18654427d..88424b54f8 100644
--- a/core/src/main/java/lucee/commons/io/res/util/UDFFilterSupport.java
+++ b/core/src/main/java/lucee/commons/io/res/util/UDFFilterSupport.java
@@ -38,7 +38,7 @@ public UDFFilterSupport(UDF udf) throws ExpressionException {
// check UDF arguments
FunctionArgument[] args = udf.getFunctionArguments();
- if (args.length > 1) throw new ExpressionException("UDF filter has too many arguments [" + args.length + "], should have at maximum 1 argument");
+ if (args.length > 3) throw new ExpressionException("UDF filter has too many arguments [" + args.length + "], should have at maximum 3 argument");
if (args.length == 1) {
type = args[0].getType();
diff --git a/core/src/main/java/lucee/commons/io/stream/SelectivePrintStream.java b/core/src/main/java/lucee/commons/io/stream/SelectivePrintStream.java
new file mode 100644
index 0000000000..f5b6c808e9
--- /dev/null
+++ b/core/src/main/java/lucee/commons/io/stream/SelectivePrintStream.java
@@ -0,0 +1,370 @@
+package lucee.commons.io.stream;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+import java.util.Locale;
+
+public class SelectivePrintStream extends PrintStream {
+
+ private final PrintStream originalPrintStream;
+ private final PrintStream interceptedOut;
+ private final long creatingThreadId;
+ private final ByteArrayOutputStream baos;
+
+ public SelectivePrintStream(PrintStream originalPrintStream) {
+ super(originalPrintStream);
+ this.originalPrintStream = originalPrintStream;
+ creatingThreadId = Thread.currentThread().getId();
+ baos = new ByteArrayOutputStream();
+ interceptedOut = new PrintStream(baos);
+ }
+
+ @Override
+ public void flush() {
+ if (intercept()) {
+ interceptedOut.flush();
+ }
+ else {
+ originalPrintStream.flush();
+ }
+ }
+
+ @Override
+ public void close() {
+ if (intercept()) {
+ interceptedOut.close();
+ }
+ else {
+ originalPrintStream.close();
+ }
+ }
+
+ @Override
+ public boolean checkError() {
+ if (intercept()) {
+ return interceptedOut.checkError();
+ }
+ else {
+ return originalPrintStream.checkError();
+ }
+ }
+
+ @Override
+ public void print(boolean b) {
+ if (intercept()) {
+ interceptedOut.print(b);
+ }
+ else {
+ originalPrintStream.print(b);
+ }
+ }
+
+ @Override
+ public void print(char c) {
+ if (intercept()) {
+ interceptedOut.print(c);
+ }
+ else {
+ originalPrintStream.print(c);
+ }
+ }
+
+ @Override
+ public void print(int i) {
+ if (intercept()) {
+ interceptedOut.print(i);
+ }
+ else {
+ originalPrintStream.print(i);
+ }
+ }
+
+ @Override
+ public void print(long l) {
+ if (intercept()) {
+ interceptedOut.print(l);
+ }
+ else {
+ originalPrintStream.print(l);
+ }
+ }
+
+ @Override
+ public void print(float f) {
+ if (intercept()) {
+ interceptedOut.print(f);
+ }
+ else {
+ originalPrintStream.print(f);
+ }
+ }
+
+ @Override
+ public void print(double d) {
+ if (intercept()) {
+ interceptedOut.print(d);
+ }
+ else {
+ originalPrintStream.print(d);
+ }
+ }
+
+ @Override
+ public void print(char[] s) {
+ if (intercept()) {
+ interceptedOut.print(s);
+ }
+ else {
+ originalPrintStream.print(s);
+ }
+ }
+
+ @Override
+ public void print(String s) {
+ if (intercept()) {
+ interceptedOut.print(s);
+ }
+ else {
+ originalPrintStream.print(s);
+ }
+ }
+
+ @Override
+ public void print(Object obj) {
+ if (intercept()) {
+ interceptedOut.print(obj);
+ }
+ else {
+ originalPrintStream.print(obj);
+ }
+ }
+
+ @Override
+ public void println() {
+ if (intercept()) {
+ interceptedOut.println();
+ }
+ else {
+ originalPrintStream.println();
+ }
+ }
+
+ @Override
+ public void println(boolean x) {
+ if (intercept()) {
+ interceptedOut.println(x);
+ }
+ else {
+ originalPrintStream.println(x);
+ }
+ }
+
+ @Override
+ public void println(char x) {
+ if (intercept()) {
+ interceptedOut.println(x);
+ }
+ else {
+ originalPrintStream.println(x);
+ }
+ }
+
+ @Override
+ public void println(int x) {
+ if (intercept()) {
+ interceptedOut.println(x);
+ }
+ else {
+ originalPrintStream.println(x);
+ }
+ }
+
+ @Override
+ public void println(long x) {
+ if (intercept()) {
+ interceptedOut.println(x);
+ }
+ else {
+ originalPrintStream.println(x);
+ }
+ }
+
+ @Override
+ public void println(float x) {
+ if (intercept()) {
+ interceptedOut.println(x);
+ }
+ else {
+ originalPrintStream.println(x);
+ }
+ }
+
+ @Override
+ public void println(double x) {
+ if (intercept()) {
+ interceptedOut.println(x);
+ }
+ else {
+ originalPrintStream.println(x);
+ }
+ }
+
+ @Override
+ public void println(char[] x) {
+ if (intercept()) {
+ interceptedOut.println(x);
+ }
+ else {
+ originalPrintStream.println(x);
+ }
+ }
+
+ @Override
+ public void println(String x) {
+ if (intercept()) {
+ interceptedOut.println(x);
+ }
+ else {
+ originalPrintStream.println(x);
+ }
+ }
+
+ @Override
+ public void println(Object x) {
+ if (intercept()) {
+ interceptedOut.println(x);
+ }
+ else {
+ originalPrintStream.println(x);
+ }
+ }
+
+ @Override
+ public PrintStream printf(String format, Object... args) {
+ if (intercept()) {
+ interceptedOut.printf(format, args);
+ return this;
+ }
+ else {
+ originalPrintStream.printf(format, args);
+ return this;
+ }
+ }
+
+ @Override
+ public PrintStream printf(Locale l, String format, Object... args) {
+ if (intercept()) {
+ interceptedOut.printf(l, format, args);
+ return this;
+ }
+ else {
+ originalPrintStream.printf(l, format, args);
+ return this;
+ }
+ }
+
+ @Override
+ public PrintStream format(String format, Object... args) {
+ if (intercept()) {
+ interceptedOut.format(format, args);
+ return this;
+ }
+ else {
+ originalPrintStream.format(format, args);
+ return this;
+ }
+ }
+
+ @Override
+ public PrintStream format(Locale l, String format, Object... args) {
+ if (intercept()) {
+ interceptedOut.format(l, format, args);
+ return this;
+ }
+ else {
+ originalPrintStream.format(l, format, args);
+ return this;
+ }
+ }
+
+ @Override
+ public PrintStream append(CharSequence csq) {
+ if (intercept()) {
+ interceptedOut.append(csq);
+ return this;
+ }
+ else {
+ originalPrintStream.append(csq);
+ return this;
+ }
+ }
+
+ @Override
+ public PrintStream append(CharSequence csq, int start, int end) {
+ if (intercept()) {
+ interceptedOut.append(csq, start, end);
+ return this;
+ }
+ else {
+ originalPrintStream.append(csq, start, end);
+ return this;
+ }
+ }
+
+ @Override
+ public PrintStream append(char c) {
+ if (intercept()) {
+ interceptedOut.append(c);
+ return this;
+ }
+ else {
+ originalPrintStream.append(c);
+ return this;
+ }
+ }
+
+ @Override
+ public void write(byte[] b) throws IOException {
+ if (intercept()) {
+ interceptedOut.write(b);
+ }
+ else {
+ originalPrintStream.write(b);
+ }
+ }
+
+ @Override
+ public void write(int b) {
+ if (intercept()) {
+ interceptedOut.write(b);
+ }
+ else {
+ originalPrintStream.write(b);
+ }
+ }
+
+ @Override
+ public void write(byte[] buf, int off, int len) {
+ if (intercept()) {
+ interceptedOut.write(buf, off, len);
+ }
+ else {
+ originalPrintStream.write(buf, off, len);
+ }
+ }
+
+ public String getInterceptedOutput() {
+ try {
+ return baos.toString("UTF-8");
+ }
+ catch (UnsupportedEncodingException e) {
+ return baos.toString();
+ }
+ }
+
+ private boolean intercept() {
+ return Thread.currentThread().getId() == creatingThreadId;
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/java/lucee/commons/lang/ClassUtil.java b/core/src/main/java/lucee/commons/lang/ClassUtil.java
index 391339f8c3..5f94f52aac 100644
--- a/core/src/main/java/lucee/commons/lang/ClassUtil.java
+++ b/core/src/main/java/lucee/commons/lang/ClassUtil.java
@@ -173,18 +173,38 @@ public static Class> loadClassByBundle(String className, BundleDefinition bund
try {
if (relatedBundles != null) {
for (BundleDefinition rb: relatedBundles) {
- rb.getBundle(id, addional, true);
+ rb.getBundle(id, addional, true, false);
}
}
return bundle.getBundle(id, addional, true, versionOnlyMattersForDownload).loadClass(className);
}
- catch (ClassNotFoundException e) {
- String appendix = "";
- if (!StringUtil.isEmpty(e.getMessage(), true)) appendix = " " + e.getMessage();
- if (bundle.getVersion() == null)
- throw new ClassException("In the OSGi Bundle with the name [" + bundle.getName() + "] was no class with name [" + className + "] found." + appendix);
- throw new ClassException("In the OSGi Bundle with the name [" + bundle.getName() + "] and the version [" + bundle.getVersion() + "] was no class with name ["
- + className + "] found." + appendix);
+ catch (ClassNotFoundException outer) {
+ try {
+ if (OSGiUtil.resolveBundleLoadingIssues(null, ThreadLocalPageContext.getConfig(), outer)) {
+ if (relatedBundles != null) {
+ for (BundleDefinition rb: relatedBundles) {
+ rb.getBundle(id, addional, true, false);
+ }
+ }
+ return bundle.getBundle(id, addional, true, versionOnlyMattersForDownload).loadClass(className);
+ }
+ else throw outer;
+
+ }
+ catch (ClassNotFoundException e) {
+ String appendix = "";
+ if (!StringUtil.isEmpty(e.getMessage(), true)) appendix = " " + e.getMessage();
+ ClassException ce;
+ if (bundle.getVersion() == null) {
+ ce = new ClassException("In the OSGi Bundle with the name [" + bundle.getName() + "] was no class with name [" + className + "] found." + appendix);
+ }
+ else {
+ ce = new ClassException("In the OSGi Bundle with the name [" + bundle.getName() + "] and the version [" + bundle.getVersion() + "] was no class with name ["
+ + className + "] found." + appendix);
+ }
+ ce.initCause(e);
+ throw ce;
+ }
}
}
@@ -405,11 +425,15 @@ public static Object loadInstance(Class clazz) throws ClassException {
return newInstance(clazz);
}
catch (InstantiationException e) {
- throw new ClassException("the specified class object [" + clazz.getName() + "()] cannot be instantiated");
+ ClassException ce = new ClassException("the specified class object [" + clazz.getName() + "()] cannot be instantiated");
+ ce.initCause(e);
+ throw ce;
}
catch (IllegalAccessException e) {
- throw new ClassException(
+ ClassException ce = new ClassException(
"can't load class [" + clazz.getName() + "] because the currently executing method does not have access to the definition of the specified class");
+ ce.initCause(e);
+ throw ce;
}
catch (Exception e) {
String message = "";
@@ -419,6 +443,7 @@ public static Object loadInstance(Class clazz) throws ClassException {
message += e.getClass().getName() + " while creating an instance of " + clazz.getName();
ClassException ce = new ClassException(message);
ce.setStackTrace(e.getStackTrace());
+ ce.initCause(e);
throw ce;
}
}
@@ -483,7 +508,9 @@ public static Object loadInstance(Class clazz, Object[] args) throws ClassExcept
}
catch (SecurityException e) {
- throw new ClassException("there is a security violation (thrown by security manager)");
+ ClassException ce = new ClassException("there is a security violation (thrown by security manager)");
+ ce.initCause(e);
+ throw ce;
}
catch (NoSuchMethodException e) {
@@ -496,16 +523,25 @@ public static Object loadInstance(Class clazz, Object[] args) throws ClassExcept
}
sb.append(')');
- throw new ClassException("there is no constructor with the [" + sb + "] signature for the class [" + clazz.getName() + "]");
+ ClassException ce = new ClassException("there is no constructor with the [" + sb + "] signature for the class [" + clazz.getName() + "]");
+ ce.initCause(e);
+ throw ce;
}
catch (IllegalArgumentException e) {
- throw new ClassException("has been passed an illegal or inappropriate argument");
+ ClassException ce = new ClassException("has been passed an illegal or inappropriate argument");
+ ce.initCause(e);
+ throw ce;
}
catch (InstantiationException e) {
- throw new ClassException("the specified class object [" + clazz.getName() + "] cannot be instantiated because it is an interface or is an abstract class");
+ ClassException ce = new ClassException(
+ "the specified class object [" + clazz.getName() + "] cannot be instantiated because it is an interface or is an abstract class");
+ ce.initCause(e);
+ throw ce;
}
catch (IllegalAccessException e) {
- throw new ClassException("can't load class because the currently executing method does not have access to the definition of the specified class");
+ ClassException ce = new ClassException("can't load class because the currently executing method does not have access to the definition of the specified class");
+ ce.initCause(e);
+ throw ce;
}
}
diff --git a/core/src/main/java/lucee/commons/lang/ExceptionUtil.java b/core/src/main/java/lucee/commons/lang/ExceptionUtil.java
index 2e0bfffaa7..cda9402ea8 100644
--- a/core/src/main/java/lucee/commons/lang/ExceptionUtil.java
+++ b/core/src/main/java/lucee/commons/lang/ExceptionUtil.java
@@ -18,10 +18,12 @@
*/
package lucee.commons.lang;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
+import java.nio.file.NoSuchFileException;
import java.util.Arrays;
import java.util.Iterator;
@@ -190,7 +192,7 @@ public static IOException toIOException(Throwable t) {
if (t instanceof NativeException) return toIOException(((NativeException) t).getCause());
IOException ioe = new IOException(t.getClass().getName() + ":" + t.getMessage());
- ioe.setStackTrace(t.getStackTrace());
+ ioe.initCause(t);
return ioe;
}
@@ -266,4 +268,10 @@ public static Throwable toThrowable(StackTraceElement[] stackTrace) {
return t;
}
+ public static FileNotFoundException toFileNotFoundException(NoSuchFileException nsfe) {
+ FileNotFoundException fnfe = new FileNotFoundException(nsfe.getMessage());
+ fnfe.initCause(nsfe);
+ return fnfe;
+ }
+
}
\ No newline at end of file
diff --git a/core/src/main/java/lucee/commons/lang/NumberUtil.java b/core/src/main/java/lucee/commons/lang/NumberUtil.java
index 3bd8a3a36e..fc6146d1d9 100644
--- a/core/src/main/java/lucee/commons/lang/NumberUtil.java
+++ b/core/src/main/java/lucee/commons/lang/NumberUtil.java
@@ -119,6 +119,6 @@ public static long byteArrayToLong(byte[] ba) {
}
public static int randomRange(int min, int max) {
- return min + (int) (ThreadLocalRandom.current().nextInt(max-min+1));
+ return min + (int) (ThreadLocalRandom.current().nextInt(max - min + 1));
}
}
\ No newline at end of file
diff --git a/core/src/main/java/lucee/commons/lang/PCLBlock.java b/core/src/main/java/lucee/commons/lang/PCLBlock.java
deleted file mode 100644
index 6d88ae592c..0000000000
--- a/core/src/main/java/lucee/commons/lang/PCLBlock.java
+++ /dev/null
@@ -1,223 +0,0 @@
-/**
- *
- * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see .
- *
- **/
-package lucee.commons.lang;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-
-import lucee.commons.io.IOUtil;
-import lucee.commons.io.SystemUtil;
-import lucee.commons.io.res.Resource;
-
-/**
- * Directory ClassLoader
- */
-public final class PCLBlock extends ExtendableClassLoader {
- static {
- boolean res = registerAsParallelCapable();
- }
- private Resource directory;
- private ClassLoader pcl;
- private int size = 0;
- private int count;
-
- /**
- * Constructor of the class
- *
- * @param directory
- * @param parent
- * @throws IOException
- */
- public PCLBlock(Resource directory, ClassLoader parent) {
- super(parent);
- this.pcl = parent;
- this.directory = directory;
- }
-
- /**
- * Loads the class with the specified name. This method searches for classes in the same manner as
- * the {@link #loadClass(String, boolean)} method. It is called by the Java virtual machine to
- * resolve class references. Calling this method is equivalent to calling
- * loadClass(name, false).
- *
- * @param name the name of the class
- * @return the resulting Class object
- * @exception ClassNotFoundException if the class was not found
- */
- @Override
- public Class> loadClass(String name) throws ClassNotFoundException {
- return loadClass(name, false);
- }// 15075171
-
- /**
- * Loads the class with the specified name. The default implementation of this method searches for
- * classes in the following order:
- *
- *
- *
- *
Call {@link #findLoadedClass(String)} to check if the class has already been loaded.
- *
- *
Call the loadClass method on the parent class loader. If the parent is
- * null the class loader built-in to the virtual machine is used, instead.
- *
- *
Call the {@link #findClass(String)} method to find the class.
- *
- *
- *
- * If the class was found using the above steps, and the resolve flag is true, this
- * method will then call the {@link #resolveClass(Class)} method on the resulting class object.
- *
- * From the Java 2 SDK, v1.2, subclasses of ClassLoader are encouraged to override
- * {@link #findClass(String)}, rather than this method.
- *
- *
- * @param name the name of the class
- * @param resolve if true then resolve the class
- * @return the resulting Class object
- * @exception ClassNotFoundException if the class could not be found
- */
- @Override
- protected synchronized Class> loadClass(String name, boolean resolve) throws ClassNotFoundException {
- // if(!name.endsWith("$cf")) return super.loadClass(name, resolve); this break Webervices
- // First, check if the class has already been loaded
- Class> c = findLoadedClass(name);
- // print.o("load:"+name+" -> "+c);
- if (c == null) {
- try {
- c = pcl.loadClass(name);// if(name.indexOf("sub")!=-1)print.ds(name);
- }
- catch (Throwable t) {
- ExceptionUtil.rethrowIfNecessary(t);
- c = findClass(name);
- }
- }
- if (resolve) {
- resolveClass(c);
- }
- return c;
- }
-
- @Override
- protected Class> findClass(String name) throws ClassNotFoundException {// if(name.indexOf("sub")!=-1)print.ds(name);
- Resource res = directory.getRealResource(name.replace('.', '/').concat(".class"));
-
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- try {
- IOUtil.copy(res, baos, false);
- }
- catch (IOException e) {
- throw new ClassNotFoundException("class " + name + " is invalid or doesn't exist");
- }
-
- byte[] barr = baos.toByteArray();
- size += barr.length;
- count++;
- IOUtil.closeEL(baos);
- return loadClass(name, barr);
- }
-
- @Override
- public Class> loadClass(String name, byte[] barr) {
- int start = 0;
- // if(ClassUtil.hasCF33Prefix(barr)) start=10;
- size += barr.length - start;
- count++;
- try {
- return defineClass(name, barr, start, barr.length - start);
- }
- catch (Throwable t) {
- ExceptionUtil.rethrowIfNecessary(t);
- SystemUtil.wait(this, 1);
- try {
- return defineClass(name, barr, start, barr.length - start);
- }
- catch (Throwable t2) {
- ExceptionUtil.rethrowIfNecessary(t2);
- SystemUtil.wait(this, 1);
- return defineClass(name, barr, start, barr.length - start);
- }
- }
- // return loadClass(name,false);
- }
-
- @Override
- public URL getResource(String name) {
- /*
- * URL url=super.getResource(name); if(url!=null) return url;
- *
- * Resource f =_getResource(name); if(f!=null) { try { return f.toURL(); } catch
- * (MalformedURLException e) {} }
- */
- return null;
- }
-
- @Override
- public InputStream getResourceAsStream(String name) {
- InputStream is = super.getResourceAsStream(name);
- if (is != null) return is;
-
- Resource f = _getResource(name);
- if (f != null) {
- try {
- return IOUtil.toBufferedInputStream(f.getInputStream());
- }
- catch (IOException e) {
- }
- }
- return null;
- }
-
- /**
- * returns matching File Object or null if file not exust
- *
- * @param name
- * @return matching file
- */
- public Resource _getResource(String name) {
- Resource f = directory.getRealResource(name);
- if (f != null && f.exists() && f.isFile()) return f;
- return null;
- }
-
- public boolean hasClass(String className) {
- return hasResource(className.replace('.', '/').concat(".class"));
- }
-
- public boolean isClassLoaded(String className) {
- // print.o("isClassLoaded:"+className+"-"+(findLoadedClass(className)!=null));
- return findLoadedClass(className) != null;
- }
-
- public boolean hasResource(String name) {
- return _getResource(name) != null;
- }
-
- /**
- * @return the directory
- */
- public Resource getDirectory() {
- return directory;
- }
-
- public int count() {
- return count;
- }
-}
\ No newline at end of file
diff --git a/core/src/main/java/lucee/commons/lang/PCLCollection.java b/core/src/main/java/lucee/commons/lang/PCLCollection.java
deleted file mode 100644
index 9d05e93438..0000000000
--- a/core/src/main/java/lucee/commons/lang/PCLCollection.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/**
- *
- * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see .
- *
- **/
-package lucee.commons.lang;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.Map;
-
-import lucee.commons.io.res.Resource;
-import lucee.runtime.MappingImpl;
-import lucee.runtime.type.util.StructUtil;
-
-/**
- * Directory ClassLoader
- */
-public final class PCLCollection {
-
- private final Resource directory;
- private final ClassLoader resourceCL;
-
- private final int maxBlockSize;
- private final MappingImpl mapping;
- private final LinkedList cfcs = new LinkedList();
- private LinkedList cfms = new LinkedList();
- private PCLBlock cfc;
- private PCLBlock cfm;
- private Map index = new HashMap();
-
- /**
- * Constructor of the class
- *
- * @param directory
- * @param parent
- * @throws IOException
- */
- public PCLCollection(MappingImpl mapping, Resource directory, ClassLoader resourceCL, int maxBlockSize) throws IOException {
- // check directory
- if (!directory.exists()) directory.mkdirs();
-
- if (!directory.isDirectory()) throw new IOException("resource " + directory + " is not a directory");
- if (!directory.canRead()) throw new IOException("no access to " + directory + " directory");
-
- this.directory = directory;
- this.mapping = mapping;
- // this.pcl=systemCL;
- this.resourceCL = resourceCL;
- cfc = new PCLBlock(directory, resourceCL);
- cfcs.add(cfc);
- cfm = new PCLBlock(directory, resourceCL);
- cfms.add(cfm);
- this.maxBlockSize = maxBlockSize;
- }
-
- private PCLBlock current(boolean isCFC) {
- if ((isCFC ? cfc.count() : cfm.count()) >= maxBlockSize) {
- synchronized (isCFC ? cfcs : cfms) {
- if (isCFC) {
- cfc = new PCLBlock(directory, resourceCL);
- cfcs.add(cfc);
- }
- else {
- cfm = new PCLBlock(directory, resourceCL);
- cfms.add(cfm);
- }
- }
- }
- return isCFC ? cfc : cfm;
- }
-
- public synchronized Class> loadClass(String name, byte[] barr, boolean isCFC) {
- // if class is already loaded flush the classloader and do new classloader
- PCLBlock block = index.get(name);
- if (block != null) {
-
- // flush classloader when update is not possible
- mapping.clearPages(block);
- StructUtil.removeValue(index, block);
- if (isCFC) {
- cfcs.remove(block);
- if (block == cfc) cfc = new PCLBlock(directory, resourceCL);
- }
- else {
- cfms.remove(block);
- if (block == cfm) cfm = new PCLBlock(directory, resourceCL);
- }
- }
-
- // load class from byte array
- PCLBlock c = current(isCFC);
- index.put(name, c);
- return c.loadClass(name, barr);
- }
-
- /**
- * load existing class
- *
- * @param name
- * @return
- * @throws ClassNotFoundException
- */
- public synchronized Class> loadClass(String className) throws ClassNotFoundException {
- // if class is already loaded flush the classloader and do new classloader
- PCLBlock cl = index.get(className);
- if (cl != null) {
- return cl.loadClass(className);
- }
- throw new ClassNotFoundException("class " + className + " not found");
- }
-
- public synchronized InputStream getResourceAsStream(String name) {
- return current(false).getResourceAsStream(name);
- }
-
- public long count() {
- return index.size();
- }
-
- /**
- * shrink the classloader elements
- *
- * @return how many page have removed from classloaders
- */
-
- public synchronized int shrink(boolean force) {
- int before = index.size();
-
- // CFM
- int flushCFM = 0;
- while (cfms.size() > 1) {
- flush(cfms.poll());
- flushCFM++;
- }
-
- // CFC
- if (force && flushCFM < 2 && cfcs.size() > 1) {
- flush(oldest(cfcs));
- if (cfcs.size() > 1) flush(cfcs.poll());
- }
- // print.o("shrink("+mapping.getVirtual()+"):"+(before-index.size())+">"+force+";"+(flushCFM));
- return before - index.size();
- }
-
- private static PCLBlock oldest(LinkedList queue) {
- int index = NumberUtil.randomRange(0, queue.size() - 2);
- return queue.remove(index);
- // return queue.poll();
- }
-
- private void flush(PCLBlock cl) {
- mapping.clearPages(cl);
- StructUtil.removeValue(index, cl);
- // System.gc(); gc is in Controller call, to make sure gc is only called once
- }
-}
diff --git a/core/src/main/java/lucee/commons/lang/PClassLoader.java b/core/src/main/java/lucee/commons/lang/PClassLoader.java
deleted file mode 100644
index cc1a6abd92..0000000000
--- a/core/src/main/java/lucee/commons/lang/PClassLoader.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/**
- * Copyright (c) 2014, the Railo Company Ltd.
- * Copyright (c) 2015, Lucee Assosication Switzerland
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see .
- *
- */
-package lucee.commons.lang;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.Enumeration;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-import lucee.commons.io.IOUtil;
-import lucee.commons.io.res.Resource;
-import lucee.runtime.config.Config;
-import lucee.runtime.config.ConfigPro;
-
-/**
- * Directory ClassLoader
- */
-public final class PClassLoader extends ClassLoader {
-
- private Resource directory;
- private ConfigPro config;
- private final ClassLoader[] parents;
-
- // Set loadedClasses = new HashSet<>();
- Set unavaiClasses = new HashSet<>();
-
- private Map customCLs;
- private Map> classes = new ConcurrentHashMap>();
-
- /**
- * Constructor of the class
- *
- * @param directory
- * @param parent
- * @throws IOException
- */
- public PClassLoader(Config c, Resource directory) throws IOException {
- this(c, directory, (ClassLoader[]) null, true);
- }
-
- public PClassLoader(Config c, Resource directory, ClassLoader[] parentClassLoaders, boolean includeCoreCL) throws IOException {
- parents = parentClassLoaders == null || parentClassLoaders.length == 0 ? new ClassLoader[] { c.getClassLoader() } : parentClassLoaders;
- config = (ConfigPro) c;
-
- // check directory
- if (!directory.exists()) directory.mkdirs();
- if (!directory.isDirectory()) throw new IOException("resource " + directory + " is not a directory");
- if (!directory.canRead()) throw new IOException("no access to " + directory + " directory");
- this.directory = directory;
- }
-
- @Override
- public Class> loadClass(String name) throws ClassNotFoundException {
- return loadClass(name, false);
- }
-
- @Override
- public Class> loadClass(String name, boolean resolve) throws ClassNotFoundException {
- Class> clazz = classes.get(name);
- if (clazz != null) return clazz;
-
- // if(unavaiClasses.contains(name)) return defaultValue;
- clazz = findClass(name, (Class) null);
- if (clazz != null) return clazz;
- return super.loadClass(name, resolve);
- }
-
- @Override
- protected Class> findClass(String name) throws ClassNotFoundException {
- Class> clazz = findClass(name, (Class) null);
- if (clazz != null) return clazz;
- return super.findClass(name);
- }
-
- @Override
- public URL getResource(String name) {
- return null;
- }
-
- @Override
- protected URL findResource(String name) {
- // TODO Auto-generated method stub
- return super.findResource(name);
- }
-
- @Override
- protected Enumeration findResources(String name) throws IOException {
- // TODO
- return super.findResources(name);
- }
-
- private Class> findClass(String name, Class> defaultValue) {
- Resource res = directory.getRealResource(name.replace('.', '/').concat(".class"));
-
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- try {
- IOUtil.copy(res, baos, false);
- }
- catch (IOException e) {
- this.unavaiClasses.add(name);
- return defaultValue;
- }
-
- byte[] barr = baos.toByteArray();
- IOUtil.closeEL(baos);
- return loadClass(name, barr);
- }
-
- public synchronized Class> loadClass(String name, byte[] barr) {
- Class> clazz = new TestClassLoader().loadClass(name, barr);
- classes.put(name, clazz);
- return clazz;
- }
-
- static class TestClassLoader extends ClassLoader {
- public Class> loadClass(String name, byte[] barr) {
- return defineClass(name, barr, 0, barr.length);
-
- }
- }
-
- @Override
- public InputStream getResourceAsStream(String name) {
- Resource f = _getResource(name);
- if (f != null) {
- try {
- return IOUtil.toBufferedInputStream(f.getInputStream());
- }
- catch (IOException e) {
- }
- }
- return null;
- }
-
- /**
- * returns matching File Object or null if file not exust
- *
- * @param name
- * @return matching file
- */
- public Resource _getResource(String name) {
- Resource f = directory.getRealResource(name);
- if (f != null && f.exists() && f.isFile()) return f;
- return null;
- }
-
- public boolean hasClass(String className) {
- return hasResource(className.replace('.', '/').concat(".class"));
- }
-
- public boolean hasResource(String name) {
- return _getResource(name) != null;
- }
-
- /**
- * @return the directory
- */
- public Resource getDirectory() {
- return directory;
- }
-}
\ No newline at end of file
diff --git a/core/src/main/java/lucee/commons/lang/PhysicalClassLoader.java b/core/src/main/java/lucee/commons/lang/PhysicalClassLoader.java
index 33ca7021bd..a0cc3a0a86 100644
--- a/core/src/main/java/lucee/commons/lang/PhysicalClassLoader.java
+++ b/core/src/main/java/lucee/commons/lang/PhysicalClassLoader.java
@@ -32,10 +32,11 @@
import lucee.commons.digest.HashUtil;
import lucee.commons.io.IOUtil;
-import lucee.commons.io.SystemUtil;
+import lucee.commons.io.log.LogUtil;
import lucee.commons.io.res.Resource;
import lucee.commons.io.res.util.ResourceClassLoader;
import lucee.commons.io.res.util.ResourceUtil;
+import lucee.runtime.PageSourcePool;
import lucee.runtime.config.Config;
import lucee.runtime.config.ConfigPro;
import lucee.runtime.exp.ApplicationException;
@@ -59,6 +60,7 @@ public final class PhysicalClassLoader extends ExtendableClassLoader {
private Map unavaiClasses = new ConcurrentHashMap();
private Map> customCLs;
+ private PageSourcePool pageSourcePool;
private static long counter = 0L;
private static long _start = 0L;
@@ -84,14 +86,15 @@ public static String uid() {
* @param parent
* @throws IOException
*/
- public PhysicalClassLoader(Config c, Resource directory) throws IOException {
- this(c, directory, (ClassLoader[]) null, true);
+ public PhysicalClassLoader(Config c, Resource directory, PageSourcePool pageSourcePool) throws IOException {
+ this(c, directory, (ClassLoader[]) null, true, pageSourcePool);
}
- public PhysicalClassLoader(Config c, Resource directory, ClassLoader[] parentClassLoaders, boolean includeCoreCL) throws IOException {
+ public PhysicalClassLoader(Config c, Resource directory, ClassLoader[] parentClassLoaders, boolean includeCoreCL, PageSourcePool pageSourcePool) throws IOException {
super(parentClassLoaders == null || parentClassLoaders.length == 0 ? c.getClassLoader() : parentClassLoaders[0]);
config = (ConfigPro) c;
+ this.pageSourcePool = pageSourcePool;
// ClassLoader resCL = parent!=null?parent:config.getResourceClassLoader(null);
List tmp = new ArrayList();
@@ -122,7 +125,7 @@ public Class> loadClass(String name) throws ClassNotFoundException {
@Override
protected Class> loadClass(String name, boolean resolve) throws ClassNotFoundException {
- synchronized (SystemUtil.createToken("PhysicalClassLoader", name)) {
+ synchronized (this) {
return loadClass(name, resolve, true);
}
}
@@ -150,7 +153,7 @@ private Class> loadClass(String name, boolean resolve, boolean loadFromFS) thr
@Override
protected Class> findClass(String name) throws ClassNotFoundException {// if(name.indexOf("sub")!=-1)print.ds(name);
- synchronized (SystemUtil.createToken("PhysicalClassLoader", name)) {
+ synchronized (this) {
Resource res = directory.getRealResource(name.replace('.', '/').concat(".class"));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -172,7 +175,7 @@ private Class> loadClass(String name, boolean resolve, boolean loadFromFS) thr
public Class> loadClass(String name, byte[] barr) throws UnmodifiableClassException {
Class> clazz = null;
- synchronized (SystemUtil.createToken("PhysicalClassLoader", name)) {
+ synchronized (this) {
// new class , not in memory yet
try {
@@ -274,7 +277,7 @@ public PhysicalClassLoader getCustomClassLoader(Resource[] resources, boolean re
SoftReference tmp = customCLs == null ? null : customCLs.get(key);
PhysicalClassLoader pcl = tmp == null ? null : tmp.get();
if (pcl != null) return pcl;
- pcl = new PhysicalClassLoader(config, getDirectory(), new ClassLoader[] { new ResourceClassLoader(resources, getParent()) }, true);
+ pcl = new PhysicalClassLoader(config, getDirectory(), new ClassLoader[] { new ResourceClassLoader(resources, getParent()) }, true, pageSourcePool);
if (customCLs == null) customCLs = new ConcurrentHashMap>();
customCLs.put(key, new SoftReference(pcl));
return pcl;
@@ -291,6 +294,11 @@ private String hash(Resource[] resources) {
}
public void clear() {
+ clear(true);
+ }
+
+ public void clear(boolean clearPagePool) {
+ if (clearPagePool && pageSourcePool != null) pageSourcePool.clearPages(this);
this.loadedClasses.clear();
this.allLoadedClasses.clear();
this.unavaiClasses.clear();
@@ -313,4 +321,16 @@ public static String substractAppendix(String name) throws ApplicationException
if (name.endsWith("$cf")) return name;
throw new ApplicationException("could not remove appendix from [" + name + "]");
}
+
+ @Override
+ public void finalize() throws Throwable {
+ try {
+ clear();
+ }
+ catch (Exception e) {
+ LogUtil.log(config, "classloader", e);
+ }
+ super.finalize();
+ }
+
}
diff --git a/core/src/main/java/lucee/commons/lang/StringUtil.java b/core/src/main/java/lucee/commons/lang/StringUtil.java
index 574ff56501..71384a82c4 100644
--- a/core/src/main/java/lucee/commons/lang/StringUtil.java
+++ b/core/src/main/java/lucee/commons/lang/StringUtil.java
@@ -838,26 +838,15 @@ public static int indexOfIgnoreCase(String haystack, String needle) {
public static int indexOfIgnoreCase(String haystack, String needle, int offset) {
if (StringUtil.isEmpty(haystack) || StringUtil.isEmpty(needle)) return -1;
- needle = needle.toLowerCase();
- if (offset > 0) haystack = haystack.substring(offset);
- else offset = 0;
+ String modHaystack = haystack.toUpperCase();
+ String modNeedle = needle.toUpperCase();
- int lenHaystack = haystack.length();
- int lenNeedle = needle.length();
-
- char lastNeedle = needle.charAt(lenNeedle - 1);
- char c;
- outer: for (int i = lenNeedle - 1; i < lenHaystack; i++) {
- c = Character.toLowerCase(haystack.charAt(i));
- if (c == lastNeedle) {
- for (int y = 0; y < lenNeedle - 1; y++) {
- if (needle.charAt(y) != Character.toLowerCase(haystack.charAt(i - (lenNeedle - 1) + y))) continue outer;
- }
- return (i - (lenNeedle - 1)) + offset;
- }
+ if (modHaystack.length() > haystack.length() || modNeedle.length() > needle.length()) {
+ modHaystack = haystack.toLowerCase();
+ modNeedle = needle.toLowerCase();
}
- return -1;
+ return offset > 0 ? modHaystack.indexOf(modNeedle, offset) : modHaystack.indexOf(modNeedle);
}
/**
@@ -1347,18 +1336,22 @@ public static String replaceStruct(String input, Struct data, boolean ignoreCase
Map positions = new LinkedHashMap<>();
String k, v;
List tmp;
+ boolean foundMatch = false;
while (it.hasNext()) {
e = it.next();
k = e.getKey().getString();
v = Caster.toString(e.getValue());
tmp = new ArrayList();
result = _replace(result.toString(), k, placeholder(k), false, ignoreCase, tmp);
+ if (!foundMatch && result instanceof StringBuilder) foundMatch = true;
for (Pos pos: tmp) {
positions.put(pos, v);
}
}
- if (result instanceof StringBuilder) {
- StringBuilder sb = (StringBuilder) result;
+ if (foundMatch) {
+ StringBuilder sb;
+ if (!(result instanceof StringBuilder)) sb = new StringBuilder().append(result);
+ else sb = (StringBuilder) result;
List> list = new ArrayList>(positions.entrySet());
// >
Collections.sort(list, new Comparator>() {
@@ -1389,19 +1382,6 @@ private static String placeholder(String str) {
return new String(carr);
}
- /*
- * public static void main(String[] args) throws PageException { Map map = new
- * HashMap<>(); map.put("target", "!target!"); map.put("replace", "er"); map.put("susi", "Susanne");
- * print.e(
- * replaceMap("I want replace replace to add 1 underscore with struct-replace... 'target' replace",
- * map, false));
- *
- * map = new HashMap<>(); map.put("Susi", "Sorglos"); map.put("Sorglos", "Susi");
- * print.e(replaceMap("Susi Sorglos foehnte ihr Haar", map, false));
- *
- * }
- */
-
public static String unwrap(String str) {
if (StringUtil.isEmpty(str)) return "";
str = str.trim();
diff --git a/core/src/main/java/lucee/commons/lang/compiler/Compiler.java b/core/src/main/java/lucee/commons/lang/compiler/Compiler.java
new file mode 100644
index 0000000000..3d3b98387f
--- /dev/null
+++ b/core/src/main/java/lucee/commons/lang/compiler/Compiler.java
@@ -0,0 +1,10 @@
+package lucee.commons.lang.compiler;
+
+import lucee.runtime.config.ConfigPro;
+import lucee.runtime.exp.PageException;
+
+public interface Compiler {
+ public boolean supported();
+
+ public byte[] compile(ConfigPro config, SourceCode sc) throws PageException, JavaCompilerException;
+}
diff --git a/core/src/main/java/lucee/commons/lang/compiler/CompilerFactory.java b/core/src/main/java/lucee/commons/lang/compiler/CompilerFactory.java
new file mode 100644
index 0000000000..206086581e
--- /dev/null
+++ b/core/src/main/java/lucee/commons/lang/compiler/CompilerFactory.java
@@ -0,0 +1,18 @@
+package lucee.commons.lang.compiler;
+
+import lucee.runtime.exp.ApplicationException;
+
+public class CompilerFactory {
+ public static Compiler getInstance() throws ApplicationException {
+ JaninoCompiler janino = new JaninoCompiler();
+ if (janino.supported()) return janino;
+
+ JVMCompiler jvm = new JVMCompiler();
+ if (jvm.supported()) return jvm;
+
+ throw new ApplicationException("Java compiling is not suppprted with your current JVM Environment (" + System.getProperty("java.vendor") + " "
+ + System.getProperty("java.version")
+ + "). Update to a newer version or add a tools.jar to the environment. Read more here: https://stackoverflow.com/questions/15513330/toolprovider-getsystemjavacompiler-returns-null-usable-with-only-jre-install");
+
+ }
+}
diff --git a/core/src/main/java/lucee/commons/lang/compiler/JavaCCompiler.java b/core/src/main/java/lucee/commons/lang/compiler/JVMCompiler.java
old mode 100755
new mode 100644
similarity index 80%
rename from core/src/main/java/lucee/commons/lang/compiler/JavaCCompiler.java
rename to core/src/main/java/lucee/commons/lang/compiler/JVMCompiler.java
index 3298e38354..ed58f296e2
--- a/core/src/main/java/lucee/commons/lang/compiler/JavaCCompiler.java
+++ b/core/src/main/java/lucee/commons/lang/compiler/JVMCompiler.java
@@ -10,18 +10,18 @@
import javax.tools.JavaFileObject;
import javax.tools.ToolProvider;
-import lucee.loader.engine.CFMLEngineFactory;
-import lucee.runtime.PageSource;
+import lucee.runtime.config.ConfigPro;
import lucee.runtime.exp.ApplicationException;
import lucee.runtime.osgi.OSGiUtil;
-/**
- * Compile Java sources in-memory
- */
-public class JavaCCompiler {
+public class JVMCompiler implements Compiler {
- public static JavaFunction compile(PageSource parent, SourceCode sc) throws JavaCompilerException, ApplicationException {
- ClassLoader cl = CFMLEngineFactory.getInstance().getCFMLEngineFactory().getClass().getClassLoader();
+ @Override
+ public byte[] compile(ConfigPro config, SourceCode sc) throws ApplicationException, JavaCompilerException {
+ ClassLoader cl = config.getClassLoaderEnv();
+
+ // ClassLoader cl =
+ // CFMLEngineFactory.getInstance().getCFMLEngineFactory().getClass().getClassLoader();
Collection compilationUnits = new ArrayList<>();
compilationUnits.add(sc);
DynamicClassLoader dcl = new DynamicClassLoader(cl);
@@ -64,6 +64,11 @@ public static JavaFunction compile(PageSource parent, SourceCode sc) throws Java
if (hasErrors) throw new JavaCompilerException(d.getMessage(Locale.US), d.getLineNumber(), d.getColumnNumber(), d.getKind());
}
}
- return new JavaFunction(parent, sc, dcl.getCompiledCode(sc.getClassName()).getByteCode());
+ return dcl.getCompiledCode(sc.getClassName()).getByteCode();
+ }
+
+ @Override
+ public boolean supported() {
+ return ToolProvider.getSystemJavaCompiler() != null;
}
}
diff --git a/core/src/main/java/lucee/commons/lang/compiler/JaninoCompiler.java b/core/src/main/java/lucee/commons/lang/compiler/JaninoCompiler.java
new file mode 100644
index 0000000000..7e76217e63
--- /dev/null
+++ b/core/src/main/java/lucee/commons/lang/compiler/JaninoCompiler.java
@@ -0,0 +1,115 @@
+package lucee.commons.lang.compiler;
+
+import java.io.File;
+import java.nio.charset.Charset;
+import java.util.List;
+
+import org.codehaus.commons.compiler.CompileException;
+import org.codehaus.commons.compiler.ICompiler;
+import org.codehaus.commons.compiler.Location;
+import org.codehaus.commons.compiler.util.resource.Resource;
+import org.codehaus.commons.compiler.util.resource.ResourceFinder;
+import org.codehaus.commons.compiler.util.resource.StringResource;
+import org.codehaus.janino.ClassLoaderIClassLoader;
+import org.codehaus.janino.CompilerFactory;
+
+import lucee.commons.lang.compiler.janino.ResourceCreatorImpl;
+import lucee.runtime.config.ConfigPro;
+import lucee.runtime.exp.PageException;
+import lucee.runtime.op.Caster;
+import lucee.runtime.osgi.OSGiUtil;
+
+public class JaninoCompiler implements Compiler {
+
+ public static void main(String[] args) throws Exception {
+ File destinationDirectory = new File("/Users/mic/Tmp3/dest");
+ File[] sourcePath = new File[0];
+ File[] classPath = { new File(".") };
+ File[] extDirs = new File[0];
+ File[] bootClassPath = null;
+ Charset encoding = Charset.defaultCharset();
+ boolean verbose = true;
+ boolean debugSource = true;
+ boolean debugLines = true;
+ boolean debugVars = false;
+ boolean rebuild = false;
+
+ // Process command line options.
+ File[] sourceFiles = new File[] { new File("/Users/mic/Documents/workspaceLuna/Testx/src/org/lucee/test/Example.java") };
+
+ ICompiler compiler = new CompilerFactory().newCompiler();
+
+ compiler.setSourcePath(sourcePath);
+
+ List list = OSGiUtil.getClassPathAsListWithJarExtension();
+ compiler.setClassPath(list.toArray(new File[list.size()]));
+ compiler.setExtensionDirectories(extDirs);
+ if (bootClassPath != null) compiler.setBootClassPath(bootClassPath); //
+ compiler.setDestinationDirectory(destinationDirectory, rebuild);
+ compiler.setVerbose(verbose);
+ compiler.setDebugSource(debugSource);
+ compiler.setDebugLines(debugLines);
+ compiler.setDebugVars(debugVars);
+ compiler.setTargetVersion(8);
+ ResourceCreatorImpl resourceCreator = new ResourceCreatorImpl();
+ compiler.setClassFileCreator(resourceCreator);
+ // Compile source files.
+ compiler.compile(new Resource[] {
+ new StringResource("Example.java", "package org.lucee.test;\n import org.osgi.framework.BundleException; public class Example {\n" + "\n" + "}") });
+
+ // compiler.setTargetVersion(0)
+
+ System.out.println(resourceCreator.getBytes(true).length);
+ }
+
+ @Override
+ public boolean supported() {
+ return true;
+ }
+
+ @Override
+ public byte[] compile(ConfigPro config, SourceCode sc) throws PageException, JavaCompilerException {
+ // Create the compiler object.
+ try {
+
+ // ClassLoader cl =
+ // CFMLEngineFactory.getInstance().getCFMLEngineFactory().getClass().getClassLoader();
+ ClassLoader cl = config.getClassLoaderEnv();
+ // ClassLoader cl = CFMLEngineFactory.getInstance().getClass().getClassLoader();
+ DynamicClassLoader dcl = new DynamicClassLoader(cl);
+ ClassLoaderIClassLoader clcl = new ClassLoaderIClassLoader(dcl);
+ ResourceFinder rf = ResourceFinder.EMPTY_RESOURCE_FINDER;
+ org.codehaus.janino.Compiler compiler = new org.codehaus.janino.Compiler(rf, clcl);
+ // ICompiler compiler = new CompilerFactory().newCompiler();
+
+ // List list = OSGiUtil.getClassPathAsListWithJarExtension(); // TODO MUST we need an update
+ // with the Janino, so it does not need a .jar extension
+ // print.e(list);
+ // compiler.setClassPath(list.toArray(new File[list.size()]));
+ compiler.setVerbose(true);
+ compiler.setDebugSource(true);
+ compiler.setDebugLines(true);
+ compiler.setDebugVars(true);
+ compiler.setTargetVersion(8);
+ ResourceCreatorImpl resourceCreator = new ResourceCreatorImpl();
+ compiler.setClassFileCreator(resourceCreator);
+ // print.e(">" + sc.getCharContent(true).toString() + "<");
+ compiler.compile(new Resource[] { new StringResource(sc.getClassName(), sc.getCharContent(true).toString()) });
+ return resourceCreator.getBytes(true);// TODO is there a more direct approch
+
+ }
+ catch (CompileException e) {
+ Throwable cause = e.getCause();
+ Location loc = e.getLocation();
+ String msg = e.getLocalizedMessage();
+ int index = msg.indexOf(':');
+ if (index != -1) msg = msg.substring(index + 1); // TODO is there a better way to do this?
+ JavaCompilerException jce = new JavaCompilerException(msg, loc.getLineNumber(), loc.getColumnNumber(), null);
+ if (cause != null) jce.initCause(cause);
+ throw jce;
+ }
+ catch (Exception e) {
+ throw Caster.toPageException(e);
+ }
+ }
+}
diff --git a/core/src/main/java/lucee/commons/lang/compiler/JarInfo.java b/core/src/main/java/lucee/commons/lang/compiler/JarInfo.java
new file mode 100644
index 0000000000..9d2bfd2fbb
--- /dev/null
+++ b/core/src/main/java/lucee/commons/lang/compiler/JarInfo.java
@@ -0,0 +1,60 @@
+package lucee.commons.lang.compiler;
+
+import java.io.IOException;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+import lucee.commons.io.IOUtil;
+import lucee.commons.io.res.Resource;
+import lucee.commons.lang.ClassUtil;
+import lucee.runtime.PageContext;
+import lucee.runtime.exp.ExpressionException;
+import lucee.runtime.op.Caster;
+
+public class JarInfo {
+
+ private static final byte[] MAJOR_VERSIONS = new byte[100];
+
+ static {
+ // java version one has a byte value of "45", java 2 "46" and so one, so that we have java 1 at
+ // position 1, we set an offset of 44
+ byte tmp = (byte) 44;
+ for (byte i = 0; i < 100; i++) {
+ MAJOR_VERSIONS[i] = tmp++;
+ }
+ }
+
+ public static int getMajorVersion(PageContext pc, String path) throws IOException, ExpressionException {
+ return getMajorVersion(Caster.toResource(pc, path, true));
+ }
+
+ public static int getMajorVersion(Resource jar) throws IOException {
+ ZipInputStream zis = null;
+ try {
+ // read the first 8 bytes of the first class listed
+ zis = new ZipInputStream(IOUtil.toBufferedInputStream(jar.getInputStream()));
+ ZipEntry entry;
+ byte[] data = null;
+ while ((entry = zis.getNextEntry()) != null) {
+ if (entry.getName().endsWith(".class")) {
+ byte[] buffer = new byte[9];
+ if (zis.read(buffer) == 9 && ClassUtil.isRawBytecode(buffer)) {
+ data = buffer;
+ }
+ }
+ zis.closeEntry();
+ if (data != null) break;
+ }
+ if (data == null || data.length < 9) throw new IOException("could not find a class to read in the jar [" + jar + "]");
+ for (int i = 0; i < MAJOR_VERSIONS.length; i++) {
+
+ if (data[7] == MAJOR_VERSIONS[i]) return i;
+ }
+ throw new IOException("could not read major version from class file in the jar [" + jar + "]");
+
+ }
+ finally {
+ IOUtil.close(zis);
+ }
+ }
+}
diff --git a/core/src/main/java/lucee/commons/lang/compiler/janino/ResourceCreatorImpl.java b/core/src/main/java/lucee/commons/lang/compiler/janino/ResourceCreatorImpl.java
new file mode 100644
index 0000000000..00438d6a09
--- /dev/null
+++ b/core/src/main/java/lucee/commons/lang/compiler/janino/ResourceCreatorImpl.java
@@ -0,0 +1,34 @@
+package lucee.commons.lang.compiler.janino;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.codehaus.commons.compiler.util.resource.ResourceCreator;
+
+public class ResourceCreatorImpl implements ResourceCreator {
+
+ private ByteArrayOutputStream baos;
+
+ @Override
+ public OutputStream createResource(String name) throws IOException {
+ baos = new ByteArrayOutputStream();
+ return baos;
+ }
+
+ @Override
+ public boolean deleteResource(String name) {
+ return true;
+ }
+
+ public byte[] getBytes(boolean release) {
+ byte[] tmp = baos.toByteArray();
+ if (release) release();
+ return tmp;
+ }
+
+ public void release() {
+ baos = null;
+ }
+
+}
diff --git a/core/src/main/java/lucee/commons/math/MathUtil.java b/core/src/main/java/lucee/commons/math/MathUtil.java
index c1d4e7150d..ca429158b2 100644
--- a/core/src/main/java/lucee/commons/math/MathUtil.java
+++ b/core/src/main/java/lucee/commons/math/MathUtil.java
@@ -84,4 +84,14 @@ public static BigDecimal multiply(BigDecimal left, BigDecimal right) {
return left.multiply(right, MathContext.DECIMAL128);
}
}
+
+ public static BigDecimal pow(BigDecimal left, int right) {
+ if (right < 0) return left.pow(right, MathContext.DECIMAL128); // negative exponent always throws
+ try {
+ return left.pow(right, MathContext.UNLIMITED);
+ }
+ catch (ArithmeticException ex) {
+ return left.pow(right, MathContext.DECIMAL128);
+ }
+ }
}
\ No newline at end of file
diff --git a/core/src/main/java/lucee/commons/net/HTTPUtil.java b/core/src/main/java/lucee/commons/net/HTTPUtil.java
index d46fb837a1..8180f566c5 100755
--- a/core/src/main/java/lucee/commons/net/HTTPUtil.java
+++ b/core/src/main/java/lucee/commons/net/HTTPUtil.java
@@ -25,6 +25,7 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
+import java.security.GeneralSecurityException;
import java.util.HashMap;
import java.util.Map;
@@ -41,6 +42,7 @@
import lucee.commons.lang.mimetype.MimeType;
import lucee.commons.net.http.HTTPEngine;
import lucee.commons.net.http.HTTPResponse;
+import lucee.commons.net.http.httpclient.HTTPEngine4Impl;
import lucee.runtime.PageContext;
import lucee.runtime.PageContextImpl;
import lucee.runtime.PageSource;
@@ -530,9 +532,10 @@ public static int getPort(URL url) {
* @param dataUrl
* @return
* @throws IOException
+ * @throws GeneralSecurityException
*/
- public static long length(URL url) throws IOException {
- HTTPResponse http = HTTPEngine.head(url, null, null, -1, true, null, Constants.NAME, null, null);
+ public static long length(URL url) throws IOException, GeneralSecurityException {
+ HTTPResponse http = HTTPEngine4Impl.head(url, null, null, -1, true, null, Constants.NAME, null, null);
long len = http.getContentLength();
HTTPEngine.closeEL(http);
return len;
diff --git a/core/src/main/java/lucee/commons/net/http/HTTPEngine.java b/core/src/main/java/lucee/commons/net/http/HTTPEngine.java
index 77286f4604..4e871ef844 100644
--- a/core/src/main/java/lucee/commons/net/http/HTTPEngine.java
+++ b/core/src/main/java/lucee/commons/net/http/HTTPEngine.java
@@ -18,8 +18,6 @@
**/
package lucee.commons.net.http;
-import java.io.IOException;
-import java.net.URL;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
@@ -30,8 +28,8 @@
import lucee.commons.io.res.Resource;
import lucee.commons.lang.StringUtil;
import lucee.commons.net.http.httpclient.HTTPEngine4Impl;
+import lucee.commons.net.http.httpclient.HTTPResponse4Impl;
import lucee.commons.net.http.httpclient.HeaderImpl;
-import lucee.runtime.net.proxy.ProxyData;
import lucee.runtime.type.util.CollectionUtil;
public class HTTPEngine {
@@ -69,58 +67,6 @@ public class HTTPEngine {
*/
public static final int STATUS_REDIRECT_SEE_OTHER = 303;
- public static HTTPResponse get(URL url) throws IOException {
- // if(use4)
- return HTTPEngine4Impl.get(url, null, null, -1, true, null, null, null, null);
- // return HTTPEngine3Impl.get(url, null, null, -1,MAX_REDIRECT, null, null, null, null);
- }
-
- public static HTTPResponse post(URL url) throws IOException {
- // if(use4)
- return HTTPEngine4Impl.post(url, null, null, -1, true, null, null, null, null);
- // return HTTPEngine3Impl.post(url, null, null, -1,MAX_REDIRECT, null, null, null, null,null);
- }
-
- public static HTTPResponse get(URL url, String username, String password, long timeout, boolean followRedirect, String charset, String useragent, ProxyData proxy,
- Header[] headers) throws IOException {
- // if(use4)
- return HTTPEngine4Impl.get(url, username, password, timeout, followRedirect, charset, useragent, proxy, headers);
- // return HTTPEngine3Impl.get(url, username, password, timeout, followRedirect?MAX_REDIRECT:0,
- // charset, useragent, proxy, headers);
- }
-
- public static HTTPResponse post(URL url, String username, String password, long timeout, boolean followRedirect, String charset, String useragent, ProxyData proxy,
- Map headers, Map params) throws IOException {
- // if(use4)
- return HTTPEngine4Impl.post(url, username, password, timeout, followRedirect, charset, useragent, proxy, toHeaders(headers), params);
- // return HTTPEngine3Impl.post(url, username, password, timeout, followRedirect?MAX_REDIRECT:0,
- // charset, useragent, proxy, toHeaders(headers),params);
- }
-
- public static HTTPResponse head(URL url, String username, String password, int timeout, boolean followRedirect, String charset, String useragent, ProxyData proxy,
- Header[] headers) throws IOException {
- // if(use4)
- return HTTPEngine4Impl.head(url, username, password, timeout, followRedirect, charset, useragent, proxy, headers);
- // return HTTPEngine3Impl.head(url, username, password, timeout, followRedirect?MAX_REDIRECT:0,
- // charset, useragent, proxy, headers);
- }
-
- public static HTTPResponse put(URL url, String username, String password, int timeout, boolean followRedirect, String mimetype, String charset, String useragent,
- ProxyData proxy, Header[] headers, Object body) throws IOException {
- // if(use4)
- return HTTPEngine4Impl.put(url, username, password, timeout, followRedirect, mimetype, charset, useragent, proxy, headers, body);
- // return HTTPEngine3Impl.put(url, username, password, timeout, followRedirect?MAX_REDIRECT:0,
- // mimetype,charset, useragent, proxy, headers,body);
- }
-
- public static HTTPResponse delete(URL url, String username, String password, int timeout, boolean followRedirect, String charset, String useragent, ProxyData proxy,
- Header[] headers) throws IOException {
- // if(use4)
- return HTTPEngine4Impl.delete(url, username, password, timeout, followRedirect, charset, useragent, proxy, headers);
- // return HTTPEngine3Impl.delete(url, username, password, timeout, followRedirect?MAX_REDIRECT:0,
- // charset, useragent, proxy, headers);
- }
-
public static Header header(String name, String value) {
// if(use4)
return HTTPEngine4Impl.header(name, value);
@@ -155,7 +101,7 @@ public static Entity getResourceEntity(Resource res, String mimetype, String cha
// return HTTPEngine3Impl.getResourceEntity(res,ct==null?null:ct.toString());
}
- private static Header[] toHeaders(Map headers) {
+ public static Header[] toHeaders(Map headers) {
if (CollectionUtil.isEmpty(headers)) return null;
Header[] rtn = new Header[headers.size()];
Iterator> it = headers.entrySet().iterator();
@@ -178,10 +124,13 @@ public static ContentType toContentType(String mimetype, String charset) {
}
public static void closeEL(HTTPResponse rsp) {
- /*
- * DISBALED BECAUSE THIS SEEM TO CAUSE PROBLEM WITH MULTITHREADING, THIS NEEDS MORE INVESTIGATION
- * if(rsp instanceof HTTPResponse4Impl) { try { ((HTTPResponse4Impl)rsp).close(); } catch (Exception
- * e) {} }
- */
+ if (rsp instanceof HTTPResponse4Impl) {
+ try {
+ ((HTTPResponse4Impl) rsp).close();
+ }
+ catch (Exception e) {
+ }
+ }
+
}
}
\ No newline at end of file
diff --git a/core/src/main/java/lucee/commons/net/http/httpclient/HTTPEngine4Impl.java b/core/src/main/java/lucee/commons/net/http/httpclient/HTTPEngine4Impl.java
index 5504b401dc..b426e5410a 100644
--- a/core/src/main/java/lucee/commons/net/http/httpclient/HTTPEngine4Impl.java
+++ b/core/src/main/java/lucee/commons/net/http/httpclient/HTTPEngine4Impl.java
@@ -22,14 +22,24 @@
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.lang.reflect.Field;
import java.net.URL;
+import java.security.GeneralSecurityException;
+import java.security.KeyManagementException;
import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
@@ -73,8 +83,8 @@
import org.apache.http.impl.client.DefaultRedirectStrategy;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
-import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.BasicHttpContext;
@@ -82,6 +92,7 @@
import lucee.commons.io.IOUtil;
import lucee.commons.io.TemporaryStream;
+import lucee.commons.io.log.LogUtil;
import lucee.commons.io.res.Resource;
import lucee.commons.lang.ExceptionUtil;
import lucee.commons.lang.StringUtil;
@@ -104,20 +115,22 @@
import lucee.runtime.op.Caster;
import lucee.runtime.op.Decision;
import lucee.runtime.tag.Http;
+import lucee.runtime.type.dt.TimeSpan;
import lucee.runtime.type.dt.TimeSpanImpl;
import lucee.runtime.type.util.CollectionUtil;
-
public class HTTPEngine4Impl {
- private static PoolingHttpClientConnectionManager connMan;
- private static Registry csfReg;
+ private static Field isShutDownField;
+ private static Map connectionManagers = new ConcurrentHashMap<>();
+ private static boolean cannotAccess = false;
public static final int POOL_MAX_CONN = 500;
public static final int POOL_MAX_CONN_PER_ROUTE = 50;
public static final int POOL_CONN_TTL_MS = 15000;
public static final int POOL_CONN_INACTIVITY_DURATION = 300;
-
+ private static final long SHUTDOWN_CHECK_MAX_AGE = 10000;
+
/**
* does a http get request
*
@@ -134,11 +147,12 @@ public class HTTPEngine4Impl {
* @param headers
* @return
* @throws IOException
+ * @throws GeneralSecurityException
*/
public static HTTPResponse get(URL url, String username, String password, long timeout, boolean redirect, String charset, String useragent, ProxyData proxy,
- lucee.commons.net.http.Header[] headers) throws IOException {
+ lucee.commons.net.http.Header[] headers) throws IOException, GeneralSecurityException {
HttpGet get = new HttpGet(url.toExternalForm());
- return _invoke(url, get, username, password, timeout, redirect, charset, useragent, proxy, headers, null);
+ return invoke(url, get, username, password, timeout, redirect, charset, useragent, proxy, headers, null, false);
}
/**
@@ -157,18 +171,19 @@ public static HTTPResponse get(URL url, String username, String password, long t
* @param headers
* @return
* @throws IOException
+ * @throws GeneralSecurityException
*/
public static HTTPResponse post(URL url, String username, String password, long timeout, boolean redirect, String charset, String useragent, ProxyData proxy,
- lucee.commons.net.http.Header[] headers) throws IOException {
+ lucee.commons.net.http.Header[] headers) throws IOException, GeneralSecurityException {
HttpPost post = new HttpPost(url.toExternalForm());
- return _invoke(url, post, username, password, timeout, redirect, charset, useragent, proxy, headers, null);
+ return invoke(url, post, username, password, timeout, redirect, charset, useragent, proxy, headers, null, false);
}
public static HTTPResponse post(URL url, String username, String password, long timeout, boolean redirect, String charset, String useragent, ProxyData proxy,
- lucee.commons.net.http.Header[] headers, Map formfields) throws IOException {
+ lucee.commons.net.http.Header[] headers, Map formfields) throws IOException, GeneralSecurityException {
HttpPost post = new HttpPost(url.toExternalForm());
- return _invoke(url, post, username, password, timeout, redirect, charset, useragent, proxy, headers, formfields);
+ return invoke(url, post, username, password, timeout, redirect, charset, useragent, proxy, headers, formfields, false);
}
/**
@@ -188,13 +203,14 @@ public static HTTPResponse post(URL url, String username, String password, long
* @param body
* @return
* @throws IOException
+ * @throws GeneralSecurityException
* @throws PageException
*/
public static HTTPResponse put(URL url, String username, String password, long timeout, boolean redirect, String mimetype, String charset, String useragent, ProxyData proxy,
- lucee.commons.net.http.Header[] headers, Object body) throws IOException {
+ lucee.commons.net.http.Header[] headers, Object body) throws IOException, GeneralSecurityException {
HttpPut put = new HttpPut(url.toExternalForm());
setBody(put, body, mimetype, charset);
- return _invoke(url, put, username, password, timeout, redirect, charset, useragent, proxy, headers, null);
+ return invoke(url, put, username, password, timeout, redirect, charset, useragent, proxy, headers, null, false);
}
@@ -214,11 +230,12 @@ public static HTTPResponse put(URL url, String username, String password, long t
* @param headers
* @return
* @throws IOException
+ * @throws GeneralSecurityException
*/
public static HTTPResponse delete(URL url, String username, String password, long timeout, boolean redirect, String charset, String useragent, ProxyData proxy,
- lucee.commons.net.http.Header[] headers) throws IOException {
+ lucee.commons.net.http.Header[] headers) throws IOException, GeneralSecurityException {
HttpDelete delete = new HttpDelete(url.toExternalForm());
- return _invoke(url, delete, username, password, timeout, redirect, charset, useragent, proxy, headers, null);
+ return invoke(url, delete, username, password, timeout, redirect, charset, useragent, proxy, headers, null, false);
}
/**
@@ -237,11 +254,12 @@ public static HTTPResponse delete(URL url, String username, String password, lon
* @param headers
* @return
* @throws IOException
+ * @throws GeneralSecurityException
*/
public static HTTPResponse head(URL url, String username, String password, long timeout, boolean redirect, String charset, String useragent, ProxyData proxy,
- lucee.commons.net.http.Header[] headers) throws IOException {
+ lucee.commons.net.http.Header[] headers) throws IOException, GeneralSecurityException {
HttpHead head = new HttpHead(url.toExternalForm());
- return _invoke(url, head, username, password, timeout, redirect, charset, useragent, proxy, headers, null);
+ return invoke(url, head, username, password, timeout, redirect, charset, useragent, proxy, headers, null, false);
}
public static lucee.commons.net.http.Header header(String name, String value) {
@@ -254,115 +272,112 @@ private static Header toHeader(lucee.commons.net.http.Header header) {
return new HeaderImpl(header.getName(), header.getValue());
}
- public static HttpClientBuilder getHttpClientBuilder() {
+ public static HttpClientBuilder getHttpClientBuilder(boolean pooling, String clientCert, String clientCertPassword) throws GeneralSecurityException, IOException {
+ String key = clientCert + ":" + clientCertPassword;
+ Registry reg = StringUtil.isEmpty(clientCert, true) ? createRegistry() : createRegistry(clientCert, clientCertPassword);
+
+ if (!pooling) {
+ HttpClientBuilder builder = HttpClients.custom();
+ HttpClientConnectionManager cm = new BasicHttpClientConnectionManager(new DefaultHttpClientConnectionOperatorImpl(reg), null);
+ builder.setConnectionManager(cm).setConnectionManagerShared(false);
+ return builder;
+ }
+
+ PoolingHttpClientConnectionManager cm = connectionManagers.get(key);
+ if (cm == null || isShutDown(cm, true)) {
+
+ // if (connMan == null || isShutDown(true)) {
+ cm = new PoolingHttpClientConnectionManager(new DefaultHttpClientConnectionOperatorImpl(reg), null, POOL_CONN_TTL_MS, TimeUnit.MILLISECONDS);
+ cm.setDefaultMaxPerRoute(POOL_MAX_CONN_PER_ROUTE);
+ cm.setMaxTotal(POOL_MAX_CONN);
+ cm.setDefaultSocketConfig(SocketConfig.copy(SocketConfig.DEFAULT).setTcpNoDelay(true).setSoReuseAddress(true).setSoLinger(0).build());
+ cm.setValidateAfterInactivity(POOL_CONN_INACTIVITY_DURATION);
+ // }
+
+ connectionManagers.put(key, cm);
+ }
HttpClientBuilder builder = HttpClients.custom();
+ builder.setConnectionManager(cm).setConnectionManagerShared(true).setConnectionTimeToLive(POOL_CONN_TTL_MS, TimeUnit.MILLISECONDS)
+ .setConnectionReuseStrategy(new DefaultClientConnectionReuseStrategy());
+
return builder;
}
- public static void setConnectionManager(HttpClientBuilder builder) throws PageException {
- setConnectionManager(builder, true);
+ public static void setTimeout(HttpClientBuilder builder, TimeSpan timeout) {
+ if (timeout == null || timeout.getMillis() <= 0) return;
+
+ int ms = (int) timeout.getMillis();
+ if (ms < 0) ms = Integer.MAX_VALUE;
+
+ SocketConfig sc = SocketConfig.custom().setSoTimeout(ms).build();
+ builder.setDefaultSocketConfig(sc);
}
- public static void setConnectionManager(HttpClientBuilder builder, boolean pooling) throws PageException {
- try {
- initDefaultConnectionFactoryRegistry();
- if (!pooling) {
- HttpClientConnectionManager cm = new BasicHttpClientConnectionManager(new DefaultHttpClientConnectionOperatorImpl(csfReg), null);
- builder.setConnectionManager(cm)
- .setConnectionManagerShared(false);
- return;
- }
- if (connMan == null) {
- connMan = new PoolingHttpClientConnectionManager(new DefaultHttpClientConnectionOperatorImpl(csfReg), null, POOL_CONN_TTL_MS, TimeUnit.MILLISECONDS);
- connMan.setDefaultMaxPerRoute(POOL_MAX_CONN_PER_ROUTE);
- connMan.setMaxTotal(POOL_MAX_CONN);
- connMan.setDefaultSocketConfig(SocketConfig.copy(SocketConfig.DEFAULT).setTcpNoDelay(true).setSoReuseAddress(true).setSoLinger(0).build());
- connMan.setValidateAfterInactivity(POOL_CONN_INACTIVITY_DURATION);
- }
- builder.setConnectionManager(connMan)
- .setConnectionManagerShared(true)
- .setConnectionTimeToLive(POOL_CONN_TTL_MS, TimeUnit.MILLISECONDS)
- .setConnectionReuseStrategy(new DefaultClientConnectionReuseStrategy());
- } catch (Exception e) {
- throw Caster.toPageException(e);
- }
+ private static Registry createRegistry() throws GeneralSecurityException {
+ SSLContext sslcontext = SSLContext.getInstance("TLS");
+ sslcontext.init(null, null, new java.security.SecureRandom());
+ SSLConnectionSocketFactory defaultsslsf = new SSLConnectionSocketFactoryImpl(sslcontext, new DefaultHostnameVerifierImpl());
+ /* Register connection handlers */
+ return RegistryBuilder.create().register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", defaultsslsf).build();
+
}
- private static void initDefaultConnectionFactoryRegistry() throws java.security.GeneralSecurityException {
- if (csfReg == null) {
- /* Default TLS settings */
- SSLContext sslcontext = SSLContext.getInstance("TLS");
- sslcontext.init(null, null, new java.security.SecureRandom());
- SSLConnectionSocketFactory defaultsslsf = new SSLConnectionSocketFactoryImpl(sslcontext, new DefaultHostnameVerifierImpl());
- /* Register connection handlers */
- csfReg = RegistryBuilder.create()
- .register("http", PlainConnectionSocketFactory.getSocketFactory())
- .register("https", defaultsslsf)
- .build();
- }
+ private static Registry createRegistry(String clientCert, String clientCertPassword)
+ throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, KeyManagementException {
+ // Currently, clientCert force usePool to being ignored
+ if (clientCertPassword == null) clientCertPassword = "";
+ // Load the client cert
+ File ksFile = new File(clientCert);
+ KeyStore clientStore = KeyStore.getInstance("PKCS12");
+ clientStore.load(new FileInputStream(ksFile), clientCertPassword.toCharArray());
+ // Prepare the keys
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ kmf.init(clientStore, clientCertPassword.toCharArray());
+ SSLContext sslcontext = SSLContext.getInstance("TLS");
+ // Configure the socket factory
+ sslcontext.init(kmf.getKeyManagers(), null, new java.security.SecureRandom());
+ SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactoryImpl(sslcontext, new DefaultHostnameVerifierImpl());
+ return RegistryBuilder.create().register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", sslsf).build();
}
- public static void setConnectionManager(HttpClientBuilder builder, boolean pooling, String clientCert, String clientCertPassword) throws PageException {
- try {
- if (StringUtil.isEmpty(clientCert)) {
- setConnectionManager(builder, pooling);
- return;
- }
- // FIXME : create a clientCert Hashmap to allow reusable connexions with client_certs
- // Currently, clientCert force usePool to being ignored
- if (clientCertPassword == null) clientCertPassword = "";
- // Load the client cert
- File ksFile = new File(clientCert);
- KeyStore clientStore = KeyStore.getInstance("PKCS12");
- clientStore.load(new FileInputStream(ksFile), clientCertPassword.toCharArray());
-
- // Prepare the keys
- KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
- kmf.init(clientStore, clientCertPassword.toCharArray());
- // Init SSL Context
- SSLContext sslcontext = SSLContext.getInstance("TLS");
- // Configure the socket factory
- sslcontext.init(kmf.getKeyManagers(), null, new java.security.SecureRandom());
- SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactoryImpl(sslcontext, new DefaultHostnameVerifierImpl());
- // Fill in the registry
- Registry reg = RegistryBuilder.create()
- .register("http", PlainConnectionSocketFactory.getSocketFactory())
- .register("https", sslsf)
- .build();
- // Provide a one off connection manager
- HttpClientConnectionManager cm = new BasicHttpClientConnectionManager(new DefaultHttpClientConnectionOperatorImpl(reg), null);
- builder.setConnectionManager(cm)
- .setConnectionManagerShared(false);
- } catch (Exception e) {
- throw Caster.toPageException(e);
+ public static void releaseConnectionManager() {
+ Collection values = connectionManagers.values();
+ connectionManagers = new ConcurrentHashMap();
+ for (PoolingHttpClientConnectionManager cm: values) {
+ IOUtil.closeEL(cm);
}
}
- public static void releaseConnectionManager() {
- if(connMan!=null) {
- connMan.close();
- connMan=null;
+ public static boolean isShutDown(PoolingHttpClientConnectionManager cm, boolean defaultValue) {
+ if (cm != null && !cannotAccess) {
+ try {
+ if (isShutDownField == null || isShutDownField.getDeclaringClass() != cm.getClass()) {
+ isShutDownField = cm.getClass().getDeclaredField("isShutDown");
+ isShutDownField.setAccessible(true);
+ }
+ return ((AtomicBoolean) isShutDownField.get(cm)).get();
+ }
+ catch (Exception e) {
+ cannotAccess = true;// depending on JRE used
+ LogUtil.log("http", e);
+ }
}
+ return defaultValue;
}
public static void closeIdleConnections() {
- if (connMan!=null) {
- connMan.closeIdleConnections(POOL_CONN_TTL_MS, TimeUnit.MILLISECONDS);
- connMan.closeExpiredConnections();
+ for (PoolingHttpClientConnectionManager cm: connectionManagers.values()) {
+ cm.closeIdleConnections(POOL_CONN_TTL_MS, TimeUnit.MILLISECONDS);
+ cm.closeExpiredConnections();
}
}
- private static HTTPResponse _invoke(URL url, HttpUriRequest request, String username, String password, long timeout, boolean redirect, String charset, String useragent,
- ProxyData proxy, lucee.commons.net.http.Header[] headers, Map formfields) throws IOException {
-
+ private static HTTPResponse invoke(URL url, HttpUriRequest request, String username, String password, long timeout, boolean redirect, String charset, String useragent,
+ ProxyData proxy, lucee.commons.net.http.Header[] headers, Map formfields, boolean pooling) throws IOException, GeneralSecurityException {
+ CloseableHttpClient client;
proxy = ProxyDataImpl.validate(proxy, url.getHost());
- HttpClientBuilder builder = getHttpClientBuilder();
- try {
- setConnectionManager(builder);
- } catch (PageException e) {
- // Ignore pooling if an issue happens
- }
+ HttpClientBuilder builder = getHttpClientBuilder(pooling, null, null);
// LDEV-2321
builder.setDefaultRequestConfig(RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build());
@@ -379,8 +394,9 @@ private static HTTPResponse _invoke(URL url, HttpUriRequest request, String user
if (timeout > 0) Http.setTimeout(builder, TimeSpanImpl.fromMillis(timeout));
HttpContext context = setCredentials(builder, hh, username, password, false);
setProxy(url.getHost(), builder, request, proxy);
- CloseableHttpClient client = builder.build();
+ client = builder.build();
if (context == null) context = new BasicHttpContext();
+
return new HTTPResponse4Impl(url, context, request, client.execute(request, context));
}
diff --git a/core/src/main/java/lucee/commons/sql/HDSQLDriver.java b/core/src/main/java/lucee/commons/sql/HDSQLDriver.java
deleted file mode 100644
index ba0dcaf5e5..0000000000
--- a/core/src/main/java/lucee/commons/sql/HDSQLDriver.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
- *
- * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see .
- *
- **/
-package lucee.commons.sql;
-
-import java.sql.Connection;
-import java.sql.SQLException;
-import java.util.Properties;
-
-import org.hsqldb.jdbcDriver;
-
-public final class HDSQLDriver extends jdbcDriver {
-
- @Override
- public Connection connect(String arg0, Properties arg1) throws SQLException {
-
- return super.connect(arg0, arg1);
- }
-
- ///
-}
\ No newline at end of file
diff --git a/core/src/main/java/lucee/commons/sql/SQLUtil.java b/core/src/main/java/lucee/commons/sql/SQLUtil.java
index 5a9abed4cf..4baa7afdba 100644
--- a/core/src/main/java/lucee/commons/sql/SQLUtil.java
+++ b/core/src/main/java/lucee/commons/sql/SQLUtil.java
@@ -216,14 +216,28 @@ public static void closeEL(ResultSet rs) {
}
public static String connectionStringTranslatedPatch(Config config, String connStr) {
- if (connStr == null || !StringUtil.startsWithIgnoreCase(connStr, "jdbc:mysql://")) return connStr;
+ if (connStr == null) return connStr;
// MySQL
- if (StringUtil.indexOfIgnoreCase(connStr, "serverTimezone=") != -1) {
- return connStr;
+ if (StringUtil.startsWithIgnoreCase(connStr, "jdbc:mysql://")) {
+ if (StringUtil.indexOfIgnoreCase(connStr, "serverTimezone=") != -1) {
+ return connStr;
+ }
+ char del = connStr.indexOf('?') != -1 ? '&' : '?';
+ return connStr + del + "serverTimezone=" + TimeZoneUtil.toString(ThreadLocalPageContext.getTimeZone(config));
+ }
+
+ // MSSQL
+ if (StringUtil.startsWithIgnoreCase(connStr, "jdbc:sqlserver://")) {
+ if (StringUtil.indexOfIgnoreCase(connStr, ";trustServerCertificate=") != -1) {
+ return connStr;
+ }
+ return connStr + (StringUtil.isEmpty(connStr, true) || connStr.endsWith(";") ? "" : ";") + "trustServerCertificate=true"; // we want default behaviour to state as
+ // before, if someone
+ // whishes encryption it can be set
+ // explicitly as the default behaviour was before
}
- char del = connStr.indexOf('?') != -1 ? '&' : '?';
- return connStr + del + "serverTimezone=" + TimeZoneUtil.toString(ThreadLocalPageContext.getTimeZone(config));
+ return connStr;
}
}
\ No newline at end of file
diff --git a/core/src/main/java/lucee/intergral/fusiondebug/server/type/FDVariable.java b/core/src/main/java/lucee/intergral/fusiondebug/server/type/FDVariable.java
index 64de4efd59..1e95191491 100644
--- a/core/src/main/java/lucee/intergral/fusiondebug/server/type/FDVariable.java
+++ b/core/src/main/java/lucee/intergral/fusiondebug/server/type/FDVariable.java
@@ -32,7 +32,7 @@ public class FDVariable implements IFDVariable {
private IFDStackFrame frame;
public FDVariable(IFDStackFrame frame, String name, IFDValue value) {
- this(frame, KeyImpl.getInstance(name), value);
+ this(frame, KeyImpl.init(name), value);
}
/**
diff --git a/core/src/main/java/lucee/runtime/CFMLFactoryImpl.java b/core/src/main/java/lucee/runtime/CFMLFactoryImpl.java
index dd943c7043..c3bba57f54 100644
--- a/core/src/main/java/lucee/runtime/CFMLFactoryImpl.java
+++ b/core/src/main/java/lucee/runtime/CFMLFactoryImpl.java
@@ -273,7 +273,7 @@ public void releaseLuceePageContext(PageContext pc) {
@Override
public void releaseLuceePageContext(PageContext pc, boolean unregisterFromThread) {
if (pc.getId() < 0) return;
- boolean isChild = pc.getParentPageContext() != null; // we need to get this check before release is executed
+ PageContext parent = pc.getParentPageContext();
// when pc was registered with an other thread, we register with this thread when calling release
PageContext beforePC = ThreadLocalPageContext.get();
@@ -295,8 +295,11 @@ public void releaseLuceePageContext(PageContext pc, boolean unregisterFromThread
if (unregisterFromThread) ThreadLocalPageContext.release();
runningPcs.remove(Integer.valueOf(pc.getId()));
- if (isChild) {
+ if (parent != null) {
runningChildPcs.remove(Integer.valueOf(pc.getId()));
+ if (parent instanceof PageContextImpl) {
+ ((PageContextImpl) parent).removeChildPageContext(pc);
+ }
}
if (pcs.size() < 100 && ((PageContextImpl) pc).getTimeoutStackTrace() == null && reuse)// not more than 100 PCs
pcs.push((PageContextImpl) pc);
@@ -347,11 +350,12 @@ public void checkTimeout() {
if (reachedConcurrentReqThreshold() && reachedMemoryThreshold() && reachedCPUThreshold()) {
if (log != null) {
PageContext root = pc.getRootPageContext();
- log.log(Log.LEVEL_ERROR, "controller",
- "stop " + (root != null && root != pc ? "thread" : "request") + " (" + pc.getId() + ") because run into a timeout. ATM we have "
- + getActiveRequests() + " active request(s) and " + getActiveThreads() + " active cfthreads " + getPath(pc) + "."
- + MonitorState.getBlockedThreads(pc) + RequestTimeoutException.locks(pc),
- ExceptionUtil.toThrowable(pc.getThread().getStackTrace()));
+ String msg = "stop " + (root != null && root != pc ? "thread" : "request") + " (" + pc.getId() + ") because run into a timeout. ATM we have "
+ + getActiveRequests() + " active request(s) and " + getActiveThreads() + " active cfthreads " + getPath(pc) + "."
+ + MonitorState.getBlockedThreads(pc) + RequestTimeoutException.locks(pc);
+ Thread thread = pc.getThread();
+ if (thread != null) log.log(Log.LEVEL_ERROR, "controller", msg, ExceptionUtil.toThrowable(thread.getStackTrace()));
+ else log.log(Log.LEVEL_ERROR, "controller", msg);
}
terminate(pc, true);
runningPcs.remove(Integer.valueOf(pc.getId()));
@@ -360,10 +364,16 @@ public void checkTimeout() {
else {
if (log != null) {
PageContext root = pc.getRootPageContext();
- log.log(Log.LEVEL_WARN, "controller", "reach request timeout with " + (root != null && root != pc ? "thread" : "request") + " [" + pc.getId()
- + "], but the request is not killed because we did not reach all thresholds set. ATM we have " + getActiveRequests() + " active request(s) and "
- + getActiveThreads() + " active cfthreads " + getPath(pc) + "." + MonitorState.getBlockedThreads(pc) + RequestTimeoutException.locks(pc),
- ExceptionUtil.toThrowable(pc.getThread().getStackTrace()));
+ boolean first = pc.timeoutNoAction() > 0;
+
+ String msg = "reach" + (first ? "" : " (again)") + " request timeout with " + (root != null && root != pc ? "thread" : "request") + " ["
+ + pc.getRequestId() + "], but the request is not killed because we did not reach all thresholds set. ATM we have " + getActiveRequests()
+ + " active request(s) and " + getActiveThreads() + " active cfthreads " + getPath(pc) + "." + MonitorState.getBlockedThreads(pc)
+ + RequestTimeoutException.locks(pc);
+
+ Thread thread = pc.getThread();
+ if (thread != null) log.log(first ? Log.LEVEL_WARN : Log.LEVEL_INFO, "controller", msg, ExceptionUtil.toThrowable(thread.getStackTrace()));
+ else log.log(first ? Log.LEVEL_WARN : Log.LEVEL_INFO, "controller", msg);
}
}
}
@@ -372,8 +382,11 @@ else if (pc.getStartTime() + 10000 < System.currentTimeMillis() && pc.getThread(
Log log = ThreadLocalPageContext.getLog(pc, "requesttimeout");
if (log != null) {
PageContext root = pc.getRootPageContext();
- log.log(Log.LEVEL_INFO, "controller", "downgrade priority of the a " + (root != null && root != pc ? "thread" : "request") + " at " + getPath(pc) + ". "
- + MonitorState.getBlockedThreads(pc) + RequestTimeoutException.locks(pc), ExceptionUtil.toThrowable(pc.getThread().getStackTrace()));
+ String msg = "downgrade priority of the a " + (root != null && root != pc ? "thread" : "request") + " at " + getPath(pc) + ". "
+ + MonitorState.getBlockedThreads(pc) + RequestTimeoutException.locks(pc);
+ Thread thread = pc.getThread();
+ if (thread != null) log.log(Log.LEVEL_INFO, "controller", msg, ExceptionUtil.toThrowable(pc.getThread().getStackTrace()));
+ else log.log(Log.LEVEL_WARN, "controller", msg);
}
try {
pc.getThread().setPriority(Thread.MIN_PRIORITY);
@@ -543,10 +556,7 @@ public Array getInfo() {
if (pc.isGatewayContext()) continue;
thread = pc.getThread();
- if (thread == Thread.currentThread()) continue;
-
- thread = pc.getThread();
- if (thread == Thread.currentThread()) continue;
+ if (thread == null || !thread.isAlive() || thread == Thread.currentThread()) continue;
data.setEL("startTime", new DateTimeImpl(pc.getStartTime(), false));
data.setEL("endTime", new DateTimeImpl(pc.getStartTime() + pc.getRequestTimeout(), false));
diff --git a/core/src/main/java/lucee/runtime/ComponentImpl.java b/core/src/main/java/lucee/runtime/ComponentImpl.java
index 69b39de587..25e48e338a 100755
--- a/core/src/main/java/lucee/runtime/ComponentImpl.java
+++ b/core/src/main/java/lucee/runtime/ComponentImpl.java
@@ -59,6 +59,8 @@
import lucee.runtime.component.DataMember;
import lucee.runtime.component.ImportDefintion;
import lucee.runtime.component.Member;
+import lucee.runtime.component.MetaDataSoftReference;
+import lucee.runtime.component.MetadataUtil;
import lucee.runtime.component.Property;
import lucee.runtime.component.StaticStruct;
import lucee.runtime.config.Config;
@@ -381,7 +383,7 @@ public void init(PageContext pageContext, ComponentPageImpl componentPage, boole
}
else {
CIPage p = ((ConfigWebPro) pageContext.getConfig()).getBaseComponentPage(pageSource.getDialect(), pageContext);
- if (!componentPage.getPageSource().equals(p.getPageSource())) {
+ if (p != null && !componentPage.getPageSource().equals(p.getPageSource())) {
base = ComponentLoader.loadComponent(pageContext, p, "Component", false, false, true, executeConstr);
}
}
@@ -430,7 +432,8 @@ public void init(PageContext pageContext, ComponentPageImpl componentPage, boole
if (!ss.isInit() || indexBase > ss.index()) {
synchronized (ss) {
// invoke static constructor
- if (!ss.isInit() || indexBase > ss.index()) {
+ boolean baseChanged = false;
+ if (!ss.isInit() || (baseChanged = (indexBase > ss.index()))) {
Map map = statConstr.get();
String id = "" + componentPage.getHash();
if (!Caster.toBooleanValue(map.get(id), false)) {
@@ -438,6 +441,7 @@ public void init(PageContext pageContext, ComponentPageImpl componentPage, boole
// this needs to happen before the call
try {
+ if (baseChanged) ss.clear();
componentPage.staticConstructor(pageContext, this);
}
catch (Throwable t) {
@@ -1003,6 +1007,21 @@ public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties
@Override
public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp, int access) {
+
+ if (pageContext != null) {
+ Member member = getMember(pageContext, KeyConstants.__toDumpData, true, false);
+ if (member instanceof UDF) {
+ UDF udf = (UDF) member;
+ if (udf.getFunctionArguments().length == 0) {
+ try {
+ return DumpUtil.toDumpData(_call(pageContext, KeyConstants.__toDumpData, udf, null, new Object[0]), pageContext, maxlevel, dp);
+ }
+ catch (PageException e) {
+ }
+ }
+ }
+ }
+
boolean isCFML = getPageSource().getDialect() == CFMLEngine.DIALECT_CFML;
DumpTable table = isCFML ? new DumpTable("component", "#48d8d8", "#68dfdf", "#000000") : new DumpTable("component", "#48d8d8", "#68dfdf", "#000000");
table.setTitle((isCFML ? "Component" : "Class") + " " + getCallPath() + (top.properties.inline ? "" : " " + StringUtil.escapeHTML(top.properties.dspName)));
@@ -1496,12 +1515,18 @@ public Object getMetaStructItem(Collection.Key name) {
}
protected static Struct getMetaData(int access, PageContext pc, ComponentImpl comp, boolean ignoreCache) throws PageException {
+ Struct existingMetaData = null;
// Cache
- /*
- * final Page page = MetadataUtil.getPageWhenMetaDataStillValid(pc, comp, ignoreCache); if (page !=
- * null && page.metaData != null && page.metaData.get() != null) { eturn page.metaData.get(); }
- */
- // long creationTime = System.currentTimeMillis();
+ final Page page = MetadataUtil.getPageWhenMetaDataStillValid(pc, comp, ignoreCache);
+ if (page != null && page.metaData != null && page.metaData.get() != null) {
+ existingMetaData = page.metaData.get();
+ if (existingMetaData != null) {
+ Struct data = Caster.toStruct(existingMetaData.get(comp.getName() + "", null), null);
+ if (data != null) return data;
+ }
+ }
+
+ long creationTime = System.currentTimeMillis();
final StructImpl sct = new StructImpl();
// fill udfs
@@ -1585,7 +1610,15 @@ protected static Struct getMetaData(int access, PageContext pc, ComponentImpl co
sct.set(KeyConstants._properties, parr);
}
- // if (page != null) page.metaData = new MetaDataSoftReference(sct, creationTime);
+ if (page != null) {
+ if (existingMetaData != null) existingMetaData.setEL(comp.getName() + "", sct);
+ else {
+ Struct coll = new StructImpl();
+ coll.setEL(comp.getName() + "", sct);
+ page.metaData = new MetaDataSoftReference(coll, creationTime);
+ }
+
+ }
return sct;
}
@@ -1833,7 +1866,7 @@ public Object get(PageContext pc, Collection.Key key) throws PageException {
}
private Object callGetter(PageContext pc, Collection.Key key) throws PageException {
- Key getterName = KeyImpl.getInstance("get" + key.getLowerString());
+ Key getterName = KeyImpl.init("get" + key.getLowerString());
Member member = getMember(pc, getterName, false, false);
if (member instanceof UDF) {
UDF udf = (UDF) member;
@@ -1845,7 +1878,7 @@ private Object callGetter(PageContext pc, Collection.Key key) throws PageExcepti
}
private Object callGetter(PageContext pc, Collection.Key key, Object defaultValue) {
- Key getterName = KeyImpl.getInstance("get" + key.getLowerString());
+ Key getterName = KeyImpl.init("get" + key.getLowerString());
Member member = getMember(pc, getterName, false, false);
if (member instanceof UDF) {
UDF udf = (UDF) member;
@@ -1862,7 +1895,7 @@ private Object callGetter(PageContext pc, Collection.Key key, Object defaultValu
}
private Object callSetter(PageContext pc, Collection.Key key, Object value) throws PageException {
- Collection.Key setterName = KeyImpl.getInstance("set" + key.getLowerString());
+ Collection.Key setterName = KeyImpl.init("set" + key.getLowerString());
Member member = getMember(pc, setterName, false, false);
if (member instanceof UDF) {
UDF udf = (UDF) member;
diff --git a/core/src/main/java/lucee/runtime/ComponentPageImpl.java b/core/src/main/java/lucee/runtime/ComponentPageImpl.java
index b9b3c9cd9c..13ba5ef4a2 100755
--- a/core/src/main/java/lucee/runtime/ComponentPageImpl.java
+++ b/core/src/main/java/lucee/runtime/ComponentPageImpl.java
@@ -22,11 +22,12 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
-import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -45,6 +46,7 @@
import lucee.runtime.converter.BinaryConverter;
import lucee.runtime.converter.ConverterException;
import lucee.runtime.converter.JSONConverter;
+import lucee.runtime.converter.JSONDateFormat;
import lucee.runtime.converter.JavaConverter;
import lucee.runtime.converter.ScriptConverter;
import lucee.runtime.converter.WDDXConverter;
@@ -53,6 +55,7 @@
import lucee.runtime.dump.DumpWriter;
import lucee.runtime.engine.ThreadLocalPageContext;
import lucee.runtime.exp.ApplicationException;
+import lucee.runtime.exp.CustomTypeException;
import lucee.runtime.exp.PageException;
import lucee.runtime.gateway.GatewayEngineImpl;
import lucee.runtime.interpreter.CFMLExpressionInterpreter;
@@ -87,11 +90,11 @@
*/
public abstract class ComponentPageImpl extends ComponentPage implements PagePro {
- public static final Collection.Key ACCEPT_ARG_COLL_FORMATS = KeyImpl.getInstance("acceptedArgumentCollectionFormats");
+ public static final Collection.Key ACCEPT_ARG_COLL_FORMATS = KeyConstants._acceptedArgumentCollectionFormats;
private static final long serialVersionUID = -3483642653131058030L;
- public static final lucee.runtime.type.Collection.Key REMOTE_PERSISTENT_ID = KeyImpl.getInstance("Id16hohohh");
+ public static final lucee.runtime.type.Collection.Key REMOTE_PERSISTENT_ID = KeyConstants._Id16hohohh;
private long lastCheck = -1;
@@ -313,9 +316,11 @@ private void callRest(PageContext pc, Component component, String path, Result r
try {
meta = udf.getMetaData(pc);
- // check if http method match
+ // check if http method either match or is unspecified
String httpMethod = Caster.toString(meta.get(KeyConstants._httpmethod, null), null);
- if (StringUtil.isEmpty(httpMethod) || !httpMethod.equalsIgnoreCase(method)) continue;
+ boolean hasHttpMethod = !StringUtil.isEmpty(httpMethod);
+ boolean httpMethodMatches = hasHttpMethod && httpMethod.equalsIgnoreCase(method);
+ if (hasHttpMethod && !httpMethodMatches) continue;
// get consumes mimetype
MimeType[] consumes;
@@ -336,7 +341,7 @@ private void callRest(PageContext pc, Component component, String path, Result r
String restPath = Caster.toString(meta.get(KeyConstants._restPath, null), null);
// no rest path
- if (StringUtil.isEmpty(restPath)) {
+ if (httpMethodMatches && StringUtil.isEmpty(restPath)) {
if (ArrayUtil.isEmpty(subPath)) {
bestC = best(consumes, result.getContentType());
bestP = best(produces, result.getAccept());
@@ -352,7 +357,15 @@ private void callRest(PageContext pc, Component component, String path, Result r
else {
Struct var = result.getVariables();
int index = RestUtil.matchPath(var, Path.init(restPath)/* TODO cache this */, result.getPath());
- if (index >= 0 && index + 1 == result.getPath().length) {
+
+ if (!hasHttpMethod && index >= 0) {
+ Result subResult = makeSubResult(result, index + 1);
+ status = 200;
+ _callThroughSubresourceLocator(pc, component, udf, path, var, subResult, suppressContent, e.getKey());
+ break;
+ }
+
+ if (httpMethodMatches && index >= 0 && index + 1 == result.getPath().length) {
bestC = best(consumes, result.getContentType());
bestP = best(produces, result.getAccept());
@@ -366,6 +379,22 @@ private void callRest(PageContext pc, Component component, String path, Result r
}
}
}
+ catch (CustomTypeException cte) {
+ ThreadLocalPageContext.getLog(pc, "rest").error("REST", cte);
+ if (cte.getCustomTypeAsString() == "RestError") {
+ try {
+ status = Integer.parseInt(cte.getErrorCode());
+ }
+ catch (NumberFormatException ne) {
+ status = 500;
+ }
+ RestUtil.setStatus(pc, status, cte.getMessage());
+ return;
+ }
+ else {
+ throw cte;
+ }
+ }
catch (PageException pe) {
ThreadLocalPageContext.getLog(pc, "rest").error("REST", pe);
throw pe;
@@ -388,6 +417,29 @@ else if (status == 406) {
}
+ private Result makeSubResult(Result r, int pathElemsToSkip) {
+ int n = r.getPath().length - pathElemsToSkip;
+ String pathElems[] = new String[n];
+ for (int i = 0; i < n; i++) {
+ pathElems[i] = r.getPath()[pathElemsToSkip + i];
+ }
+ List acceptList = Arrays.asList(r.getAccept());
+ Result subResult = new Result(r.getSource(), r.getVariables(), pathElems, r.getMatrix(), r.getFormat(), r.hasFormatExtension(), acceptList, r.getContentType());
+ return subResult;
+ }
+
+ private void _callThroughSubresourceLocator(PageContext pc, Component component, UDF udf, String path, Struct variables, Result result, boolean suppressContent, Key methodName)
+ throws PageException, IOException, ConverterException {
+ Object rtn = _callUDF(pc, component, udf, variables, result, suppressContent, methodName);
+ if (rtn instanceof Component) {
+ Component subcomp = (Component) rtn;
+ callRest(pc, subcomp, path, result, suppressContent);
+ }
+ else {
+ RestUtil.setStatus(pc, 500, "Subresource locator error.");
+ }
+ }
+
private MimeType best(MimeType[] produces, MimeType... accept) {
if (ArrayUtil.isEmpty(produces)) {
if (accept.length > 0) return accept[0];
@@ -408,24 +460,32 @@ private MimeType best(MimeType[] produces, MimeType... accept) {
return best;
}
- private void _callRest(PageContext pc, Component component, UDF udf, String path, Struct variables, Result result, MimeType best, MimeType[] produces, boolean suppressContent,
- Key methodName) throws PageException, IOException, ConverterException {
+ private Object _callUDF(PageContext pc, Component component, UDF udf, Struct variables, Result result, boolean suppressContent, Key methodName) throws PageException {
FunctionArgument[] fa = udf.getFunctionArguments();
Struct args = new StructImpl(), meta;
Key name;
+ List arrName = new ArrayList();
+ List arrRestArgSource = new ArrayList();
+ List arrRestArgName = new ArrayList();
String restArgName, restArgSource, value;
for (int i = 0; i < fa.length; i++) {
- name = fa[i].getName();
+
+ arrName.add(fa[i].getName());
meta = fa[i].getMetaData();
- restArgSource = meta == null ? "" : Caster.toString(meta.get(KeyConstants._restArgSource, ""), "");
+ arrRestArgSource.add(meta == null ? "" : Caster.toString(meta.get(KeyConstants._restArgSource, ""), ""));
+ arrRestArgName.add(meta == null ? "" : Caster.toString(meta.get(KeyConstants._restArgName, ""), ""));
+ }
+ for (int i = 0; i < fa.length; i++) {
+ name = arrName.get(i);
+ restArgSource = arrRestArgSource.get(i);
if ("path".equalsIgnoreCase(restArgSource)) setValue(fa[i], args, name, variables.get(name, null));
if ("query".equalsIgnoreCase(restArgSource) || "url".equalsIgnoreCase(restArgSource)) setValue(fa[i], args, name, pc.urlScope().get(name, null));
if ("form".equalsIgnoreCase(restArgSource)) setValue(fa[i], args, name, pc.formScope().get(name, null));
if ("cookie".equalsIgnoreCase(restArgSource)) setValue(fa[i], args, name, pc.cookieScope().get(name, null));
if ("header".equalsIgnoreCase(restArgSource) || "head".equalsIgnoreCase(restArgSource)) {
- restArgName = meta == null ? "" : Caster.toString(meta.get(KeyConstants._restArgName, ""), "");
+ restArgName = arrRestArgName.get(i);
if (StringUtil.isEmpty(restArgName)) restArgName = name.getString();
value = ReqRspUtil.getHeaderIgnoreCase(pc, restArgName, null);
setValue(fa[i], args, name, value);
@@ -433,9 +493,21 @@ private void _callRest(PageContext pc, Component component, UDF udf, String path
if ("matrix".equalsIgnoreCase(restArgSource)) setValue(fa[i], args, name, result.getMatrix().get(name, null));
if ("body".equalsIgnoreCase(restArgSource) || StringUtil.isEmpty(restArgSource, true)) {
+ // cfargument cannot have the attributes restArgSource and restArgName specified. That is, you can
+ // only send data in the body of the request.
+ if (!StringUtil.isEmpty(arrRestArgName.get(i), true)) {
+ continue;
+ }
+ else if (!"body".equalsIgnoreCase(restArgSource)) {
+ // There can only be one argument that does not specify the restArgSource attribute.
+ for (int j = 0; j < fa.length; j++) {
+ if (StringUtil.isEmpty(arrRestArgSource.get(j)) && i != j) continue;
+ }
+ }
boolean isSimple = CFTypes.isSimpleType(fa[i].getType());
- Object body = ReqRspUtil.getRequestBody(pc, true, null);
- if (isSimple && !Decision.isSimpleValue(body)) body = ReqRspUtil.getRequestBody(pc, false, null);
+ Object body;
+ if (isSimple) body = ReqRspUtil.getRequestBody(pc, false, null);
+ else body = ReqRspUtil.getRequestBody(pc, true, null);
setValue(fa[i], args, name, body);
}
}
@@ -452,6 +524,13 @@ private void _callRest(PageContext pc, Component component, UDF udf, String path
finally {
if (suppressContent) pc.unsetSilent();
}
+ return rtn;
+ }
+
+ private void _callRest(PageContext pc, Component component, UDF udf, String path, Struct variables, Result result, MimeType best, MimeType[] produces, boolean suppressContent,
+ Key methodName) throws PageException, IOException, ConverterException {
+
+ Object rtn = _callUDF(pc, component, udf, variables, result, suppressContent, methodName);
// custom response
Struct sct = result.getCustomResponse();
@@ -592,7 +671,7 @@ public static boolean isSoap(PageContext pc) {
private void callWDDX(PageContext pc, Component component, Collection.Key methodName, boolean suppressContent) throws PageException {
try {
// Struct url = StructUtil.duplicate(pc.urlFormScope(),true);
- Struct url = StructUtil.merge(new Struct[] { pc.formScope(), pc.urlScope() });
+ Struct url = StructUtil.merge(false, new Struct[] { pc.formScope(), pc.urlScope() });
// define args
url.removeEL(KeyConstants._fieldnames);
url.removeEL(KeyConstants._method);
@@ -801,13 +880,13 @@ else if (UDF.RETURN_FORMAT_JSON == props.format) {
if (qf == SerializationSettings.SERIALIZE_AS_UNDEFINED)
throw new ApplicationException("invalid queryformat definition [" + queryFormat + "], valid formats are [row,column,struct]");
}
- JSONConverter converter = new JSONConverter(false, cs);
+ JSONConverter converter = new JSONConverter(false, cs, JSONDateFormat.PATTERN_CF, true);
String prefix = "";
if (props.secureJson) {
prefix = pc.getApplicationContext().getSecureJsonPrefix();
if (prefix == null) prefix = "";
}
- pc.forceWrite(prefix + converter.serialize(pc, rtn, qf));
+ pc.forceWrite(prefix + converter.serialize(pc, rtn, qf, true));
}
// CFML
else if (UDF.RETURN_FORMAT_SERIALIZE == props.format) {
@@ -908,8 +987,8 @@ private void callCFCMetaData(PageContext pc, Component cfc, int format) throws I
else if (UDF.RETURN_FORMAT_JSON == format) {
int qf = SerializationSettings.SERIALIZE_AS_ROW;
cs = getCharset(pc);
- JSONConverter converter = new JSONConverter(false, cs);
- String str = converter.serialize(pc, rtn, qf);
+ JSONConverter converter = new JSONConverter(false, cs, JSONDateFormat.PATTERN_CF, false);
+ String str = converter.serialize(pc, rtn, qf, true);
is = new ByteArrayInputStream(str.getBytes(cs));
}
@@ -963,7 +1042,7 @@ private Charset getCharset(PageContext pc) {
return cs;
}
- private void callWSDL(PageContext pc, Component component) throws ServletException, IOException, PageException {
+ private void callWSDL(PageContext pc, Component component) throws IOException, PageException {
// take wsdl file defined by user
String wsdl = component.getWSDLFile();
if (!StringUtil.isEmpty(wsdl)) {
@@ -988,7 +1067,7 @@ private void callWSDL(PageContext pc, Component component) throws ServletExcepti
}
}
- private void callWebservice(PageContext pc, Component component) throws IOException, ServletException, PageException {
+ private void callWebservice(PageContext pc, Component component) throws IOException, PageException {
((ConfigWebPro) ThreadLocalPageContext.getConfig(pc)).getWSHandler().getWSServer(pc).doPost(pc, pc.getHttpServletRequest(), pc.getHttpServletResponse(), component);
}
diff --git a/core/src/main/java/lucee/runtime/ComponentProperties.java b/core/src/main/java/lucee/runtime/ComponentProperties.java
index fd50a9a98a..9c3b8cb469 100644
--- a/core/src/main/java/lucee/runtime/ComponentProperties.java
+++ b/core/src/main/java/lucee/runtime/ComponentProperties.java
@@ -24,12 +24,12 @@
import lucee.runtime.component.Property;
import lucee.runtime.exp.ExpressionException;
import lucee.runtime.type.Collection;
-import lucee.runtime.type.KeyImpl;
import lucee.runtime.type.Struct;
+import lucee.runtime.type.util.KeyConstants;
public class ComponentProperties implements Serializable {
- private static final Collection.Key WSDL_FILE = KeyImpl.getInstance("wsdlfile");
+ private static final Collection.Key WSDL_FILE = KeyConstants._wsdlfile;
final String dspName;
final String extend;
final String hint;
diff --git a/core/src/main/java/lucee/runtime/InterfaceImpl.java b/core/src/main/java/lucee/runtime/InterfaceImpl.java
index 53de503883..bfa09d8cec 100755
--- a/core/src/main/java/lucee/runtime/InterfaceImpl.java
+++ b/core/src/main/java/lucee/runtime/InterfaceImpl.java
@@ -39,6 +39,7 @@
import lucee.runtime.engine.ThreadLocalPageContext;
import lucee.runtime.exp.ApplicationException;
import lucee.runtime.exp.PageException;
+import lucee.runtime.op.Caster;
import lucee.runtime.type.ArrayImpl;
import lucee.runtime.type.Collection;
import lucee.runtime.type.KeyImpl;
@@ -204,7 +205,14 @@ public Struct getMetaData(PageContext pc, boolean ignoreCache) throws PageExcept
private static Struct _getMetaData(PageContext pc, InterfaceImpl icfc, boolean ignoreCache) throws PageException {
Page page = MetadataUtil.getPageWhenMetaDataStillValid(pc, icfc, ignoreCache);
- if (page != null && page.metaData != null && page.metaData.get() != null) return page.metaData.get();
+ Struct existingMetaData = null;
+ if (page != null && page.metaData != null && page.metaData.get() != null) {
+ existingMetaData = page.metaData.get();
+ if (existingMetaData != null) {
+ Struct data = Caster.toStruct(existingMetaData.get(icfc._getName() + "", null), null);
+ if (data != null) return data;
+ }
+ }
long creationTime = System.currentTimeMillis();
@@ -251,7 +259,16 @@ private static Struct _getMetaData(PageContext pc, InterfaceImpl icfc, boolean i
sct.set(KeyConstants._path, ps.getDisplayPath());
sct.set(KeyConstants._type, "interface");
- page.metaData = new MetaDataSoftReference(sct, creationTime);
+ if (page != null) {
+ if (existingMetaData != null) existingMetaData.setEL(icfc._getName() + "", sct);
+ else {
+ Struct coll = new StructImpl();
+ coll.setEL(icfc._getName() + "", sct);
+ page.metaData = new MetaDataSoftReference(coll, creationTime);
+ }
+
+ }
+
return sct;
}
diff --git a/core/src/main/java/lucee/runtime/MappingImpl.java b/core/src/main/java/lucee/runtime/MappingImpl.java
index 0969e020ce..9da6abd88e 100755
--- a/core/src/main/java/lucee/runtime/MappingImpl.java
+++ b/core/src/main/java/lucee/runtime/MappingImpl.java
@@ -23,7 +23,7 @@
import java.io.Serializable;
import java.lang.instrument.UnmodifiableClassException;
import java.lang.ref.SoftReference;
-import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -35,11 +35,10 @@
import lucee.commons.io.FileUtil;
import lucee.commons.io.IOUtil;
-import lucee.commons.io.log.Log;
+import lucee.commons.io.log.LogUtil;
import lucee.commons.io.res.Resource;
import lucee.commons.lang.ExceptionUtil;
import lucee.commons.lang.MappingUtil;
-import lucee.commons.lang.PCLCollection;
import lucee.commons.lang.PhysicalClassLoader;
import lucee.commons.lang.StringUtil;
import lucee.loader.engine.CFMLEngine;
@@ -63,9 +62,6 @@ public final class MappingImpl implements Mapping {
private static final long serialVersionUID = 6431380676262041196L;
- private static final int MAX_SIZE_CFC = 3000;// 6783;
- private static final int MAX_SIZE_CFM = 2000;// 6783;
-
private static final Class SUBPAGE_CONSTR = PageSource.class;
private String virtual;
@@ -73,12 +69,9 @@ public final class MappingImpl implements Mapping {
private boolean topLevel;
private short inspect;
private boolean physicalFirst;
- private transient PhysicalClassLoader pclCFM;
- private transient PhysicalClassLoader pclCFC;
- private transient PCLCollection pcoll;
+ private transient Map loaders = new HashMap<>();
private Resource archive;
- private boolean hasArchive;
private final Config config;
private Resource classRootDirectory;
private final PageSourcePool pageSourcePool = new PageSourcePool();
@@ -137,8 +130,8 @@ public MappingImpl(Config config, String virtual, String strPhysical, String str
this.config = config;
this.hidden = hidden;
this.readonly = readonly;
- this.strPhysical = StringUtil.isEmpty(strPhysical) ? null : strPhysical;
- this.strArchive = StringUtil.isEmpty(strArchive) ? null : strArchive;
+ this.strPhysical = StringUtil.isEmpty(strPhysical, true) ? null : strPhysical.trim();
+ this.strArchive = StringUtil.isEmpty(strArchive, true) ? null : strArchive.trim();
this.inspect = inspect;
this.topLevel = topLevel;
this.appMapping = appMapping;
@@ -155,23 +148,23 @@ public MappingImpl(Config config, String virtual, String strPhysical, String str
else this.virtual = virtual;
this.lcVirtual = this.virtual.toLowerCase();
this.lcVirtualWithSlash = lcVirtual.endsWith("/") ? this.lcVirtual : this.lcVirtual + '/';
+ }
+ private void initPhysical() {
ServletContext cs = (config instanceof ConfigWeb) ? ((ConfigWeb) config).getServletContext() : null;
+ physical = ConfigWebUtil.getResource(cs, strPhysical, config.getConfigDir(), FileUtil.TYPE_DIR, config, checkPhysicalFromWebroot, false);
+ if (archive == null) this.physicalFirst = true;
+ else if (physical == null) this.physicalFirst = false;
- // Physical
- physical = ConfigWebUtil.getExistingResource(cs, strPhysical, null, config.getConfigDir(), FileUtil.TYPE_DIR, config, checkPhysicalFromWebroot);
- // Archive
- archive = ConfigWebUtil.getExistingResource(cs, strArchive, null, config.getConfigDir(), FileUtil.TYPE_FILE, config, checkArchiveFromWebroot);
- loadArchive();
+ }
- hasArchive = archive != null;
+ private void initArchive() {
+ ServletContext cs = (config instanceof ConfigWeb) ? ((ConfigWeb) config).getServletContext() : null;
+ archive = ConfigWebUtil.getResource(cs, strArchive, config.getConfigDir(), FileUtil.TYPE_FILE, config, checkArchiveFromWebroot, true);
+ loadArchive();
if (archive == null) this.physicalFirst = true;
else if (physical == null) this.physicalFirst = false;
- else this.physicalFirst = physicalFirst;
-
- // if(!hasArchive && !hasPhysical) throw new IOException("missing physical and archive path, one of
- // them must be defined");
}
private void loadArchive() {
@@ -180,18 +173,19 @@ private void loadArchive() {
CFMLEngine engine = ConfigWebUtil.getEngine(config);
BundleContext bc = engine.getBundleContext();
try {
- archiveBundle = OSGiUtil.installBundle(bc, archive, true);
+ archiveBundle = OSGiUtil.installBundle(bc, getArchive(), true);
}
catch (Throwable t) {
ExceptionUtil.rethrowIfNecessary(t);
archMod = archive.lastModified();
- ThreadLocalPageContext.getLog(config, "application").log(Log.LEVEL_ERROR, "OSGi", t);
+ LogUtil.log(config, "OSGi", t);
archive = null;
}
}
@Override
public Class> getArchiveClass(String className) throws ClassNotFoundException {
+ getArchive();// this calls init the archive if necessary
if (archiveBundle != null) {
return archiveBundle.loadClass(className);
}
@@ -201,6 +195,7 @@ public Class> getArchiveClass(String className) throws ClassNotFoundException
@Override
public Class> getArchiveClass(String className, Class> defaultValue) {
+ getArchive();// this calls init the archive if necessary
try {
if (archiveBundle != null) return archiveBundle.loadClass(className);
// else if(archiveClassLoader!=null) return archiveClassLoader.loadClass(className);
@@ -234,34 +229,54 @@ public Class> loadClass(String className) {
return null;
}
- public PCLCollection touchClassLoader() throws IOException {
- if (pcoll == null) {
- pcoll = new PCLCollection(this, getClassRootDirectory(), getConfig().getClassLoader(), 100);
+ private Class> loadClass(String className, byte[] code) throws IOException, ClassNotFoundException {
+
+ PhysicalClassLoaderReference pclr = loaders.get(className);
+ PhysicalClassLoader pcl = pclr == null ? null : pclr.get();
+ if (pcl == null || code != null) {// || pcl.getSize(true) > 3
+ if (pcl != null) {
+ pcl.clear();
+ }
+ pcl = new PhysicalClassLoader(config, getClassRootDirectory(), pageSourcePool);
+ synchronized (loaders) {
+ loaders.put(className, new PhysicalClassLoaderReference(pcl));
+ }
}
- return pcoll;
- }
- private PhysicalClassLoader touchPhysicalClassLoader(boolean forComponent) throws IOException {
- if (forComponent ? pclCFC == null : pclCFM == null) {
- if (forComponent) pclCFC = new PhysicalClassLoader(config, getClassRootDirectory());
- else pclCFM = new PhysicalClassLoader(config, getClassRootDirectory());
+ if (code != null) {
+ try {
+ return pcl.loadClass(className, code);
+ }
+ catch (UnmodifiableClassException e) {
+ throw ExceptionUtil.toIOException(e);
+ }
}
- else if ((forComponent ? pclCFC : pclCFM).getSize(true) > (forComponent ? MAX_SIZE_CFC : MAX_SIZE_CFM)) {
- PhysicalClassLoader pcl = forComponent ? pclCFC : pclCFM;
- synchronized (pageSourcePool) {
- pageSourcePool.clearPages(pcl);
+ return pcl.loadClass(className);
+ }
+
+ public void cleanLoaders() {
+ pageSourcePool.cleanLoaders();
+ }
+
+ public void clear(String className) {
+ PhysicalClassLoaderReference ref = loaders.remove(className);
+ PhysicalClassLoader pcl;
+ if (ref != null) {
+ pcl = ref.get();
+ if (pcl != null) {
+ pcl.clear(false);
}
- pcl.clear();
- if (forComponent) pclCFC = new PhysicalClassLoader(config, getClassRootDirectory());
- else pclCFM = new PhysicalClassLoader(config, getClassRootDirectory());
}
- return forComponent ? pclCFC : pclCFM;
+ }
+
+ public int getSize() {
+ return loaders.size();
}
@Override
public Class> getPhysicalClass(String className) throws ClassNotFoundException, IOException {
- return touchPhysicalClassLoader(className.contains("_cfc$cf")).loadClass(className);
- // return touchClassLoader().loadClass(className);
+ return loadClass(className, null);
+ // return touchPhysicalClassLoader(className.contains("_cfc$cf")).loadClass(className);
}
public Class> getPhysicalClass(String className, Class> defaultValue) {
@@ -275,14 +290,15 @@ public Class> getPhysicalClass(String className, Class> defaultValue) {
@Override
public Class> getPhysicalClass(String className, byte[] code) throws IOException {
-
try {
- return touchPhysicalClassLoader(className.contains("_cfc$cf")).loadClass(className, code);
+ return loadClass(className, code);
}
- catch (UnmodifiableClassException e) {
- throw new IOException(e);
+ catch (Exception e) {
+ throw ExceptionUtil.toIOException(e);
}
+ // return touchPhysicalClassLoader(className.contains("_cfc$cf")).loadClass(className, code);
+
// boolean isCFC = className.indexOf("_cfc$")!=-1;//aaaa ResourceUtil.getExtension(ps.getRealpath(),
// "").equalsIgnoreCase("cfc");
// return touchClassLoader().loadClass(className,code,isCFC);
@@ -294,25 +310,20 @@ public Class> getPhysicalClass(String className, byte[] code) throws IOExcepti
* @param cl
*/
public void clearPages(ClassLoader cl) {
- synchronized (pageSourcePool) {
- pageSourcePool.clearPages(cl);
- }
+ pageSourcePool.clearPages(cl);
}
- public void clearUnused(Config config) {
- synchronized (pageSourcePool) {
- pageSourcePool.clearUnused(config);
- }
+ public void clearUnused() {
+ pageSourcePool.cleanLoaders();
}
public void resetPages(ClassLoader cl) {
- synchronized (pageSourcePool) {
- pageSourcePool.resetPages(cl);
- }
+ pageSourcePool.resetPages(cl);
}
@Override
public Resource getPhysical() {
+ if (physical == null && strPhysical != null) initPhysical(); // possible that the target path only exists AFTER startup
return physical;
}
@@ -328,18 +339,18 @@ public String getVirtualLowerCaseWithSlash() {
@Override
public Resource getArchive() {
- // initArchive();
+ if (archive == null && strArchive != null) initArchive(); // possible that the target path only exists AFTER startup
return archive;
}
@Override
public boolean hasArchive() {
- return hasArchive;
+ return getArchive() != null;
}
@Override
public boolean hasPhysical() {
- return physical != null;
+ return getPhysical() != null;
}
@Override
@@ -360,8 +371,8 @@ public Resource getClassRootDirectory() {
* @throws IOException
*/
public MappingImpl cloneReadOnly(Config config) {
- return new MappingImpl(config, virtual, ConfigWebUtil.replacePlaceholder(strPhysical, config), ConfigWebUtil.replacePlaceholder(strArchive, config), inspect, physicalFirst,
- hidden, true, topLevel, appMapping, ignoreVirtual, appListener, listenerMode, listenerType, checkPhysicalFromWebroot, checkArchiveFromWebroot);
+ return new MappingImpl(config, virtual, strPhysical, strArchive, inspect, physicalFirst, hidden, true, topLevel, appMapping, ignoreVirtual, appListener, listenerMode,
+ listenerType, checkPhysicalFromWebroot, checkArchiveFromWebroot);
}
@Override
@@ -398,71 +409,69 @@ else if (realPath.startsWith("./")) {
return getPageSource(realPath, isOutSide);
}
+ public Resource getResource(String realPath) {
+ // TODO merge the functionality with the method above
+ boolean isOutSide = false;
+ realPath = realPath.replace('\\', '/');
+ if (realPath.indexOf('/') != 0) {
+ if (realPath.startsWith("../")) {
+ isOutSide = true;
+ }
+ else if (realPath.startsWith("./")) {
+ realPath = realPath.substring(1);
+ }
+ else {
+ realPath = "/" + realPath;
+ }
+ }
+ return getResource(realPath, isOutSide);
+ }
+
@Override
public PageSource getPageSource(String path, boolean isOut) {
- synchronized (pageSourcePool) {
- PageSource source = pageSourcePool.getPageSource(path, true);
- if (source != null) return source;
+ PageSource source = pageSourcePool.getPageSource(path, true);
+ if (source != null) return source;
- PageSourceImpl newSource = new PageSourceImpl(this, path, isOut);
- pageSourcePool.setPage(path, newSource);
+ PageSourceImpl newSource = new PageSourceImpl(this, path, isOut);
+ pageSourcePool.setPage(path, newSource);
- return newSource;// new PageSource(this,path);
- }
+ return newSource;// new PageSource(this,path);
+ }
+
+ /**
+ * in contrust to getPageSource this function will not store the requested path in the pool and
+ *
+ * @param path
+ * @param isOut
+ * @return
+ */
+ public Resource getResource(String path, boolean isOut) {
+ // TODO rewrite so PageSourceImpl not need to be loaded
+ return new PageSourceImpl(this, path, isOut).getResource();
}
// to not delete,used for argus monitor!
public PageSourcePool getPageSourcePool() {
- synchronized (pageSourcePool) {
- return pageSourcePool;
- }
+ return pageSourcePool;
}
public Array getDisplayPathes(Array arr) throws PageException {
- synchronized (pageSourcePool) {
- String[] keys = pageSourcePool.keys();
- PageSourceImpl ps;
- for (int y = 0; y < keys.length; y++) {
- ps = (PageSourceImpl) pageSourcePool.getPageSource(keys[y], false);
- if (ps != null && ps.isLoad()) arr.append(ps.getDisplayPath());
- }
- return arr;
+ List values = pageSourcePool.values(true);
+ for (PageSource ps: values) {
+ if (ps != null) arr.append(ps.getDisplayPath());
}
+ return arr;
}
public List getPageSources(boolean loaded) {
- List list = new ArrayList<>();
- synchronized (pageSourcePool) {
- String[] keys = pageSourcePool.keys();
- PageSourceImpl ps;
- for (int y = 0; y < keys.length; y++) {
- ps = (PageSourceImpl) pageSourcePool.getPageSource(keys[y], false);
- if (ps != null) {
- if (!loaded || ps.isLoad()) list.add(ps);
- }
- }
- }
- return list;
+ return pageSourcePool.values(loaded);
}
@Override
public void check() {
- ServletContext cs = (config instanceof ConfigWeb) ? ((ConfigWeb) config).getServletContext() : null;
-
- // Physical
- if (getPhysical() == null && strPhysical != null && strPhysical.length() > 0) {
- physical = ConfigWebUtil.getExistingResource(cs, strPhysical, null, config.getConfigDir(), FileUtil.TYPE_DIR, config, checkPhysicalFromWebroot);
-
- }
- // Archive
- if (getArchive() == null && strArchive != null && strArchive.length() > 0) {
-
- archive = ConfigWebUtil.getExistingResource(cs, strArchive, null, config.getConfigDir(), FileUtil.TYPE_FILE, config, checkArchiveFromWebroot);
- loadArchive();
-
- hasArchive = archive != null;
-
- }
+ // make sure everything is loaded
+ getPhysical();
+ getArchive();
}
@Override
@@ -477,6 +486,8 @@ public boolean isHidden() {
@Override
public boolean isPhysicalFirst() {
+ check();
+ // now we can trust the result
return physicalFirst;
}
@@ -599,9 +610,7 @@ public int getListenerType() {
}
public void flush() {
- synchronized (pageSourcePool) {
- pageSourcePool.clear();
- }
+ pageSourcePool.clear();
}
public SerMapping toSerMapping() {
@@ -638,14 +647,33 @@ public static CIPage loadCIPage(PageSource ps, String className) {
try {
MappingImpl m = ((MappingImpl) ps.getMapping());
Resource res = m.getClassRootDirectory().getRealResource(className + ".class");
- Class> clazz = m.touchPhysicalClassLoader(true).loadClass(className.replace('/', '.').replace('\\', '.'), IOUtil.toBytes(res));
-
+ String cn = className.replace('/', '.').replace('\\', '.');
+ Class> clazz = m.loadClass(cn, IOUtil.toBytes(res));
return (CIPage) clazz.getConstructor(SUBPAGE_CONSTR).newInstance(ps);
- // return (CIPage) ((Class>) ((MappingImpl)
- // ps.getMapping()).loadClass(className)).getConstructor(SUBPAGE_CONSTR).newInstance(ps);
}
catch (Exception e) {
throw Caster.toPageRuntimeException(e);
}
}
+
+ private static class PhysicalClassLoaderReference extends SoftReference {
+
+ private long lastModified;
+
+ public PhysicalClassLoaderReference(PhysicalClassLoader pcl) {
+ super(pcl);
+ this.lastModified = System.currentTimeMillis();
+ }
+
+ @Override
+ public PhysicalClassLoader get() {
+ this.lastModified = System.currentTimeMillis();
+ return super.get();
+ }
+
+ public long lastModified() {
+ return lastModified;
+ }
+ }
+
}
\ No newline at end of file
diff --git a/core/src/main/java/lucee/runtime/PageContextImpl.java b/core/src/main/java/lucee/runtime/PageContextImpl.java
index 3531b6a081..14ae4d6c54 100755
--- a/core/src/main/java/lucee/runtime/PageContextImpl.java
+++ b/core/src/main/java/lucee/runtime/PageContextImpl.java
@@ -49,7 +49,6 @@
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
-import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.el.ExpressionEvaluator;
import javax.servlet.jsp.el.VariableResolver;
@@ -168,6 +167,7 @@
import lucee.runtime.type.Collection.Key;
import lucee.runtime.type.Iterator;
import lucee.runtime.type.KeyImpl;
+import lucee.runtime.type.LiteralValue;
import lucee.runtime.type.Query;
import lucee.runtime.type.SVArray;
import lucee.runtime.type.Struct;
@@ -365,6 +365,7 @@ public final class PageContextImpl extends PageContext {
private static final boolean READ_CFID_FROM_URL = Caster.toBooleanValue(SystemUtil.getSystemPropOrEnvVar("lucee.read.cfid.from.url", "true"), true);
private static int _idCounter = 1;
+ private long lastTimeoutNoAction;
/**
* default Constructor
@@ -694,8 +695,8 @@ public void release() {
timeZone = null;
url = null;
form = null;
- currentTemplateDialect = CFMLEngine.DIALECT_LUCEE;
- requestDialect = CFMLEngine.DIALECT_LUCEE;
+ currentTemplateDialect = CFMLEngine.DIALECT_CFML;
+ requestDialect = CFMLEngine.DIALECT_CFML;
// Pools
errorPagePool.clear();
@@ -754,7 +755,7 @@ public void release() {
_psq = null;
dummy = false;
listenSettings = false;
-
+ if (lastTimeoutNoAction != 0) lastTimeoutNoAction = 0L;
if (ormSession != null) {
try {
releaseORM();
@@ -900,7 +901,7 @@ public PageSource getPageSource(String realPath) {
}
public PageSource[] getPageSources(String realPath) { // to not change, this is used in the flex extension
- return config.getPageSources(this, applicationContext.getMappings(), realPath, false, useSpecialMappings, true);
+ return config.getPageSources(this, applicationContext.getMappings(), realPath, false, useSpecialMappings, true, false);
}
public PageSource getPageSourceExisting(String realPath) { // do not change, this method is used in flex extension
@@ -1250,7 +1251,91 @@ public Undefined us() {
return undefined;
}
+ public Object us(Collection.Key key) throws PageException {
+ if (!undefined.isInitalized()) undefined.initialize(this);
+ return undefined.get(key);
+ }
+
+ public Object us(Collection.Key key1, Collection.Key key2) throws PageException {
+ if (!undefined.isInitalized()) undefined.initialize(this);
+ return variableUtil.get(this, undefined.getCollection(key1), key2);
+ }
+
+ public Object us(Collection.Key key1, Collection.Key key2, Collection.Key key3) throws PageException {
+ if (!undefined.isInitalized()) undefined.initialize(this);
+ return variableUtil.get(this, variableUtil.getCollection(this, undefined.getCollection(key1), key2), key3);
+ }
+
+ public Object us(Collection.Key key1, Collection.Key key2, Collection.Key key3, Collection.Key key4) throws PageException {
+ if (!undefined.isInitalized()) undefined.initialize(this);
+ return variableUtil.get(this, variableUtil.getCollection(this, variableUtil.getCollection(this, undefined.getCollection(key1), key2), key3), key4);
+ }
+
+ public Object us(Collection.Key key1, Collection.Key key2, Collection.Key key3, Collection.Key key4, Collection.Key key5) throws PageException {
+ if (!undefined.isInitalized()) undefined.initialize(this);
+ return variableUtil.get(this,
+ variableUtil.getCollection(this, variableUtil.getCollection(this, variableUtil.getCollection(this, undefined.getCollection(key1), key2), key3), key4), key5);
+ }
+
+ public Object usc(Collection.Key key1, Collection.Key key2) throws PageException {
+ if (!undefined.isInitalized()) undefined.initialize(this);
+ return variableUtil.getCollection(this, undefined.getCollection(key1), key2);
+ }
+
+ public Object usc(Collection.Key key1, Collection.Key key2, Collection.Key key3) throws PageException {
+ if (!undefined.isInitalized()) undefined.initialize(this);
+ return variableUtil.getCollection(this, variableUtil.getCollection(this, undefined.getCollection(key1), key2), key3);
+ }
+
+ public Object usc(Collection.Key key1, Collection.Key key2, Collection.Key key3, Collection.Key key4) throws PageException {
+ if (!undefined.isInitalized()) undefined.initialize(this);
+ return variableUtil.getCollection(this, variableUtil.getCollection(this, variableUtil.getCollection(this, undefined.getCollection(key1), key2), key3), key4);
+ }
+
+ public Object usc(Collection.Key key1, Collection.Key key2, Collection.Key key3, Collection.Key key4, Collection.Key key5) throws PageException {
+ if (!undefined.isInitalized()) undefined.initialize(this);
+ return variableUtil.getCollection(this,
+ variableUtil.getCollection(this, variableUtil.getCollection(this, variableUtil.getCollection(this, undefined.getCollection(key1), key2), key3), key4), key5);
+ }
+
+ public Object us(Collection.Key key, Object value) throws PageException {
+ if (!undefined.isInitalized()) undefined.initialize(this);
+ undefined.set(key, value);
+ return value;
+ }
+
+ public Object us(Collection.Key key1, Collection.Key key2, Object value) throws PageException {
+ if (!undefined.isInitalized()) undefined.initialize(this);
+
+ Object o = undefined.get(key1, null);
+ if (o == null) {
+ o = undefined.set(key1, new StructImpl());
+ }
+ return set(o, key2, value);
+ }
+
+ public Object us(Collection.Key key1, Collection.Key key2, Collection.Key key3, Object value) throws PageException {
+ if (!undefined.isInitalized()) undefined.initialize(this);
+ // key 1
+ Object o = undefined.get(key1, null);
+ if (o == null) {
+ o = undefined.set(key1, new StructImpl());
+ }
+ return set(touch(o, key2), key3, value);
+ }
+
+ public Object us(Collection.Key key1, Collection.Key key2, Collection.Key key3, Collection.Key key4, Object value) throws PageException {
+ if (!undefined.isInitalized()) undefined.initialize(this);
+ // key 1
+ Object o = undefined.get(key1, null);
+ if (o == null) {
+ o = undefined.set(key1, new StructImpl());
+ }
+ return set(touch(touch(o, key2), key3), key4, value);
+ }
+
public Scope usl() {
+
if (!undefined.isInitalized()) undefined.initialize(this);
if (undefined.getCheckArguments()) return undefined.localScope();
return undefined;
@@ -1261,6 +1346,63 @@ public Variables variablesScope() {
return variables;
}
+ public Object vs(Collection.Key key) throws PageException {
+ return variables.get(key);
+ }
+
+ public Object vs(Collection.Key key1, Collection.Key key2) throws PageException {
+ return variableUtil.get(this, variables.get(key1), key2);
+ }
+
+ public Object vs(Collection.Key key1, Collection.Key key2, Collection.Key key3) throws PageException {
+ return variableUtil.get(this, variableUtil.getCollection(this, variables.get(key1), key2), key3);
+ }
+
+ public Object vs(Collection.Key key1, Collection.Key key2, Collection.Key key3, Collection.Key key4) throws PageException {
+ return variableUtil.get(this, variableUtil.getCollection(this, variableUtil.getCollection(this, variables.get(key1), key2), key3), key4);
+ }
+
+ public Object vsc(Collection.Key key1, Collection.Key key2) throws PageException {
+ return variableUtil.getCollection(this, variables.get(key1), key2);
+ }
+
+ public Object vsc(Collection.Key key1, Collection.Key key2, Collection.Key key3) throws PageException {
+ return variableUtil.getCollection(this, variableUtil.getCollection(this, variables.get(key1), key2), key3);
+ }
+
+ public Object vsc(Collection.Key key1, Collection.Key key2, Collection.Key key3, Collection.Key key4) throws PageException {
+ return variableUtil.getCollection(this, variableUtil.getCollection(this, variableUtil.getCollection(this, variables.get(key1), key2), key3), key4);
+ }
+
+ public Object vs(Collection.Key key, Object value) throws PageException {
+ variables.set(key, value);
+ return value;
+ }
+
+ public Object vs(Collection.Key key1, Collection.Key key2, Object value) throws PageException {
+ Object o = variables.get(key1, null);
+ if (o == null) {
+ o = variables.set(key1, new StructImpl());
+ }
+ return set(o, key2, value);
+ }
+
+ public Object vs(Collection.Key key1, Collection.Key key2, Collection.Key key3, Object value) throws PageException {
+ Object o = variables.get(key1, null);
+ if (o == null) {
+ o = variables.set(key1, new StructImpl());
+ }
+ return set(touch(o, key2), key3, value);
+ }
+
+ public Object vs(Collection.Key key1, Collection.Key key2, Collection.Key key3, Collection.Key key4, Object value) throws PageException {
+ Object o = variables.get(key1, null);
+ if (o == null) {
+ o = variables.set(key1, new StructImpl());
+ }
+ return set(touch(touch(o, key2), key3), key4, value);
+ }
+
@Override
public URL urlScope() {
if (!url.isInitalized()) url.initialize(this);
@@ -1322,11 +1464,90 @@ public Argument argumentsScope(boolean bind) {
@Override
public Local localScope() {
- // if(local==localUnsupportedScope)
- // throw new PageRuntimeException(new ExpressionException("Unsupported Context for Local Scope"));
return local;
}
+ public Object ls(Collection.Key key) throws PageException {
+ if (!undefined.getCheckArguments()) return us(KeyConstants._local, key);
+ return local.get(key);
+ }
+
+ public Object ls(Collection.Key key1, Collection.Key key2) throws PageException {
+ if (!undefined.getCheckArguments()) return us(KeyConstants._local, key1, key2);
+ return variableUtil.get(this, local.get(key1), key2);
+ }
+
+ public Object ls(Collection.Key key1, Collection.Key key2, Collection.Key key3) throws PageException {
+ if (!undefined.getCheckArguments()) return us(KeyConstants._local, key1, key2, key3);
+ return variableUtil.get(this, variableUtil.getCollection(this, local.get(key1), key2), key3);
+ }
+
+ public Object ls(Collection.Key key1, Collection.Key key2, Collection.Key key3, Collection.Key key4) throws PageException {
+ if (!undefined.getCheckArguments()) return us(KeyConstants._local, key1, key2, key3, key4);
+ return variableUtil.get(this, variableUtil.getCollection(this, variableUtil.getCollection(this, local.get(key1), key2), key3), key4);
+ }
+
+ public Object lsc(Collection.Key key1, Collection.Key key2) throws PageException {
+ if (!undefined.getCheckArguments()) return usc(KeyConstants._local, key1, key2);
+ return variableUtil.getCollection(this, local.get(key1), key2);
+ }
+
+ public Object lsc(Collection.Key key1, Collection.Key key2, Collection.Key key3) throws PageException {
+ if (!undefined.getCheckArguments()) return usc(KeyConstants._local, key1, key2, key3);
+ return variableUtil.getCollection(this, variableUtil.getCollection(this, local.get(key1), key2), key3);
+ }
+
+ public Object lsc(Collection.Key key1, Collection.Key key2, Collection.Key key3, Collection.Key key4) throws PageException {
+ if (!undefined.getCheckArguments()) return usc(KeyConstants._local, key1, key2, key3, key4);
+ return variableUtil.getCollection(this, variableUtil.getCollection(this, variableUtil.getCollection(this, local.get(key1), key2), key3), key4);
+ }
+
+ public Object ls(Collection.Key key, Object value) throws PageException {
+ if (!undefined.getCheckArguments()) return us(KeyConstants._local, key, value);
+
+ local.set(key, value);
+ return value;
+ }
+
+ public Object ls(Collection.Key key1, Collection.Key key2, Object value) throws PageException {
+ if (!undefined.getCheckArguments()) return us(KeyConstants._local, key1, key2, value);
+
+ Object o = local.get(key1, null);
+ if (o == null) {
+ o = local.set(key1, new StructImpl());
+ }
+ return set(o, key2, value);
+ }
+
+ public Object ls(Collection.Key key1, Collection.Key key2, Collection.Key key3, Object value) throws PageException {
+ if (!undefined.getCheckArguments()) return us(KeyConstants._local, key1, key2, key3, value);
+
+ Object o = local.get(key1, null);
+ if (o == null) {
+ o = local.set(key1, new StructImpl());
+ }
+ return set(touch(o, key2), key3, value);
+ }
+
+ public Object ls(Collection.Key key1, Collection.Key key2, Collection.Key key3, Collection.Key key4, Object value) throws PageException {
+ LiteralValue.toNumber(this, 1L);
+
+ if (!undefined.getCheckArguments()) {
+ if (!undefined.isInitalized()) undefined.initialize(this);
+ Object o = undefined.get(KeyConstants._local, null);
+ if (o == null) {
+ o = undefined.set(KeyConstants._local, new StructImpl());
+ }
+ return set(touch(touch(touch(o, key1), key2), key3), key4, value);
+ }
+
+ Object o = local.get(key1, null);
+ if (o == null) {
+ o = local.set(key1, new StructImpl());
+ }
+ return set(touch(touch(o, key2), key3), key4, value);
+ }
+
@Override
public Local localScope(boolean bind) {
if (bind) local.setBind(true);
@@ -2478,9 +2699,9 @@ else if (type.equalsIgnoreCase("customtag")) {
base = getPageSource(config.getCustomTagMappings(), realPath.substring(index));
}
}
- if (base == null) base = PageSourceImpl.best(config.getPageSources(this, null, realPath, onlyTopLevel, false, true));
+ if (base == null) base = PageSourceImpl.best(config.getPageSources(this, null, realPath, onlyTopLevel, false, true, false));
}
- else base = PageSourceImpl.best(config.getPageSources(this, null, realPath, onlyTopLevel, false, true));
+ else base = PageSourceImpl.best(config.getPageSources(this, null, realPath, onlyTopLevel, false, true, false));
execute(base, throwExcpetion, onlyTopLevel);
}
@@ -2647,16 +2868,16 @@ public String getCFToken() {
@Override
public String getURLToken() {
- if (getConfig().getSessionType() == Config.SESSION_TYPE_JEE) {
+ if (getSessionType() == Config.SESSION_TYPE_JEE) {
HttpSession s = getSession();
- return "CFID=" + getCFID() + "&CFTOKEN=" + getCFToken() + "&jsessionid=" + (s != null ? s.getId() : "");
+ return "CFID=" + getCFID() + "&CFTOKEN=" + getCFToken() + "&jsessionid=" + (s != null ? getSession().getId() : "");
}
return "CFID=" + getCFID() + "&CFTOKEN=" + getCFToken();
}
@Override
public String getJSessionId() {
- if (getConfig().getSessionType() == Config.SESSION_TYPE_JEE) {
+ if (getSessionType() == Config.SESSION_TYPE_JEE) {
return getSession().getId();
}
return null;
@@ -2764,6 +2985,7 @@ private void setClientCookies() {
boolean secure = SessionCookieDataImpl.DEFAULT.isSecure();
short samesite = SessionCookieDataImpl.DEFAULT.getSamesite();
String path = SessionCookieDataImpl.DEFAULT.getPath();
+ boolean partitioned = SessionCookieDataImpl.DEFAULT.isPartitioned();
ApplicationContext ac = getApplicationContext();
@@ -2786,6 +3008,8 @@ private void setClientCookies() {
// path
String tmp2 = data.getPath();
if (!StringUtil.isEmpty(tmp2, true)) path = tmp2.trim();
+ // partitioned
+ partitioned = data.isPartitioned();
}
}
int expires;
@@ -2793,8 +3017,8 @@ private void setClientCookies() {
if (Integer.MAX_VALUE < tmp) expires = Integer.MAX_VALUE;
else expires = (int) tmp;
- ((CookieImpl) cookieScope()).setCookieEL(KeyConstants._cfid, cfid, expires, secure, path, domain, httpOnly, true, false, samesite);
- ((CookieImpl) cookieScope()).setCookieEL(KeyConstants._cftoken, cftoken, expires, secure, path, domain, httpOnly, true, false, samesite);
+ ((CookieImpl) cookieScope()).setCookieEL(KeyConstants._cfid, cfid, expires, secure, path, domain, httpOnly, true, false, samesite, partitioned);
+ ((CookieImpl) cookieScope()).setCookieEL(KeyConstants._cftoken, cftoken, expires, secure, path, domain, httpOnly, true, false, samesite, partitioned);
}
@@ -2913,10 +3137,15 @@ public void reuse(Tag tag, String tagBundleName, String tagBundleVersion) {
}
@Override
- public void initBody(BodyTag bodyTag, int state) throws JspException {
+ public void initBody(BodyTag bodyTag, int state) throws PageException {
if (state != Tag.EVAL_BODY_INCLUDE) {
bodyTag.setBodyContent(pushBody());
- bodyTag.doInitBody();
+ try {
+ bodyTag.doInitBody();
+ }
+ catch (Exception e) {
+ throw Caster.toPageException(e);
+ }
}
}
@@ -3043,11 +3272,11 @@ public void _setCatch(PageException pe, String name, boolean caught, boolean sto
Undefined u = undefinedScope();
if (pe == null) {
(u.getCheckArguments() ? u.localScope() : u).removeEL(KeyConstants._cfcatch);
- if (name != null && !StringUtil.isEmpty(name, true)) (u.getCheckArguments() ? u.localScope() : u).removeEL(KeyImpl.getInstance(name.trim()));
+ if (name != null && !StringUtil.isEmpty(name, true)) (u.getCheckArguments() ? u.localScope() : u).removeEL(KeyImpl.init(name.trim()));
}
else {
(u.getCheckArguments() ? u.localScope() : u).setEL(KeyConstants._cfcatch, pe.getCatchBlock(config));
- if (name != null && !StringUtil.isEmpty(name, true)) (u.getCheckArguments() ? u.localScope() : u).setEL(KeyImpl.getInstance(name.trim()), pe.getCatchBlock(config));
+ if (name != null && !StringUtil.isEmpty(name, true)) (u.getCheckArguments() ? u.localScope() : u).setEL(KeyImpl.init(name.trim()), pe.getCatchBlock(config));
if (!gatewayContext && config.debug() && config.hasDebugOptions(ConfigPro.DEBUG_EXCEPTION)) {
/*
* print.e("-----------------------"); print.e("msg:" + pe.getMessage()); print.e("caught:" +
@@ -3373,6 +3602,10 @@ public Queue getChildPageContexts() {
return children;
}
+ public boolean removeChildPageContext(PageContext pc) {
+ return children.remove(pc);
+ }
+
@Override
public String[] getThreadScopeNames() {
if (threads == null) return new String[0];
@@ -3907,4 +4140,15 @@ private static synchronized int getIdCounter() {
if (_idCounter < 0) _idCounter = 1;
return _idCounter;
}
+
+ public boolean limitEvaluation() {
+ if (applicationContext != null) return applicationContext.getLimitEvaluation();
+ return ((ConfigPro) config).limitEvaluation();
+ }
+
+ public long timeoutNoAction() {
+ long tmp = lastTimeoutNoAction;
+ lastTimeoutNoAction = System.currentTimeMillis();
+ return tmp;
+ }
}
diff --git a/core/src/main/java/lucee/runtime/PageSourceImpl.java b/core/src/main/java/lucee/runtime/PageSourceImpl.java
index 06559336d2..9c53182773 100755
--- a/core/src/main/java/lucee/runtime/PageSourceImpl.java
+++ b/core/src/main/java/lucee/runtime/PageSourceImpl.java
@@ -210,7 +210,7 @@ public PageSource getParent() {
}
@Override
- public synchronized Page loadPage(PageContext pc, boolean forceReload) throws PageException {
+ public Page loadPage(PageContext pc, boolean forceReload) throws PageException {
if (forceReload) pcn.reset();
Page page = pcn.page;
@@ -229,7 +229,7 @@ public synchronized Page loadPage(PageContext pc, boolean forceReload) throws Pa
}
@Override
- public synchronized Page loadPageThrowTemplateException(PageContext pc, boolean forceReload, Page defaultValue) throws TemplateException {
+ public Page loadPageThrowTemplateException(PageContext pc, boolean forceReload, Page defaultValue) throws TemplateException {
if (forceReload) pcn.reset();
Page page = pcn.page;
@@ -247,7 +247,7 @@ public synchronized Page loadPageThrowTemplateException(PageContext pc, boolean
}
@Override
- public synchronized Page loadPage(PageContext pc, boolean forceReload, Page defaultValue) {
+ public Page loadPage(PageContext pc, boolean forceReload, Page defaultValue) {
if (forceReload) pcn.reset();
Page page = pcn.page;
@@ -278,17 +278,19 @@ public synchronized Page loadPage(PageContext pc, boolean forceReload, Page defa
private Page loadArchive(Page page) {
if (!mapping.hasArchive()) return null;
if (page != null && page.getLoadType() == LOAD_ARCHIVE) return page;
- try {
- Class clazz = mapping.getArchiveClass(getClassName());
- page = newInstance(clazz);
- page.setPageSource(this);
- page.setLoadType(LOAD_ARCHIVE);
- pcn.set(page);
- return page;
- }
- catch (Exception e) {
- // MUST print.e(e); is there a better way?
- return null;
+ synchronized (this) {
+ try {
+ Class clazz = mapping.getArchiveClass(getClassName());
+ page = newInstance(clazz);
+ page.setPageSource(this);
+ page.setLoadType(LOAD_ARCHIVE);
+ pcn.set(page);
+ return page;
+ }
+ catch (Exception e) {
+ // MUST print.e(e); is there a better way?
+ return null;
+ }
}
}
@@ -309,35 +311,41 @@ private Page loadPhysical(PageContext pc, Page page) throws TemplateException {
long srcLastModified = srcFile.lastModified();
if (srcLastModified == 0L) return null;
-
// Page exists
if (page != null) {
// if(page!=null && !recompileAlways) {
if (srcLastModified != page.getSourceLastModified() || (page instanceof PagePro && ((PagePro) page).getSourceLength() != srcFile.length())) {
- // same size, maybe the content has not changed?
- boolean same = false;
- if (page instanceof PagePro && ((PagePro) page).getSourceLength() == srcFile.length()) {
- PagePro pp = (PagePro) page;
- try {
- same = pp.getHash() == PageSourceCode.toString(this, config.getTemplateCharset()).hashCode();
- }
- catch (IOException e) {
- }
+ synchronized (this) {
+ if (srcLastModified != page.getSourceLastModified() || (page instanceof PagePro && ((PagePro) page).getSourceLength() != srcFile.length())) {
+ // same size, maybe the content has not changed?
+ boolean same = false;
+ if (page instanceof PagePro && ((PagePro) page).getSourceLength() == srcFile.length()) {
+ PagePro pp = (PagePro) page;
+ try {
+ same = pp.getHash() == PageSourceCode.toString(this, config.getTemplateCharset()).hashCode();
+ }
+ catch (IOException e) {
+ }
- }
- if (!same) {
- LogUtil.log(pc, Log.LEVEL_DEBUG, "compile", "recompile [" + getDisplayPath() + "] because loaded page has changed");
- pcn.set(page = compile(config, mapping.getClassRootDirectory(), page, false, pc.ignoreScopes()));
- page.setPageSource(this);
+ }
+ if (!same) {
+ LogUtil.log(pc, Log.LEVEL_DEBUG, "compile", "recompile [" + getDisplayPath() + "] because loaded page has changed");
+ pcn.set(page = compile(config, mapping.getClassRootDirectory(), page, false, pc.ignoreScopes()));
+ page.setPageSource(this);
+ }
+ }
}
}
page.setLoadType(LOAD_PHYSICAL);
+ pci.setPageUsed(page); //
+ return page;
}
+
// page doesn't exist
- else {
- Resource classRootDir = mapping.getClassRootDirectory();
- Resource classFile = classRootDir.getRealResource(getJavaName() + ".class");
- boolean isNew = false;
+ Resource classRootDir = mapping.getClassRootDirectory();
+ Resource classFile = classRootDir.getRealResource(getJavaName() + ".class");
+ boolean isNew = false;
+ synchronized (this) {
// new class
if (flush || !classFile.exists()) {
LogUtil.log(pc, Log.LEVEL_DEBUG, "compile", "compile [" + getDisplayPath() + "] no previous class file or flush");
@@ -909,6 +917,23 @@ else if (realPath.startsWith("./")) {
return mapping.getPageSource(realPath, _isOutSide.toBooleanValue());
}
+ public Resource getRealResource(String realPath) {
+ if (realPath.equals(".") || realPath.equals("..")) realPath += '/';
+ else realPath = realPath.replace('\\', '/');
+ RefBoolean _isOutSide = new RefBooleanImpl(isOutSide);
+
+ if (realPath.indexOf('/') == 0) {
+ _isOutSide.setValue(false);
+ }
+ else if (realPath.startsWith("./")) {
+ realPath = mergeRealPathes(mapping, this.relPath, realPath.substring(2), _isOutSide);
+ }
+ else {
+ realPath = mergeRealPathes(mapping, this.relPath, realPath, _isOutSide);
+ }
+ return mapping.getResource(realPath, _isOutSide.toBooleanValue());
+ }
+
@Override
public final void setLastAccessTime(long lastAccess) {
this.lastAccess = lastAccess;
@@ -969,6 +994,7 @@ public Resource getResourceTranslated(PageContext pc) throws ExpressionException
}
public void clear() {
+ mapping.clear(pcn.className);
pcn.page = null;
}
@@ -1002,6 +1028,15 @@ public static PageSource best(PageSource[] arr) {
return arr[0];
}
+ public static Resource best(Resource[] arr) {
+ if (ArrayUtil.isEmpty(arr)) return null;
+ if (arr.length == 1) return arr[0];
+ for (int i = 0; i < arr.length; i++) {
+ if (arr[i] != null && arr[i].exists()) return arr[i];
+ }
+ return arr[0];
+ }
+
public static boolean pageExist(PageSource ps) {
return (ps.getMapping().isTrusted() && ((PageSourceImpl) ps).isLoad()) || ps.exists();
}
diff --git a/core/src/main/java/lucee/runtime/PageSourcePool.java b/core/src/main/java/lucee/runtime/PageSourcePool.java
index cb9afe9023..1c316b3a2d 100644
--- a/core/src/main/java/lucee/runtime/PageSourcePool.java
+++ b/core/src/main/java/lucee/runtime/PageSourcePool.java
@@ -19,21 +19,23 @@
package lucee.runtime;
import java.lang.ref.SoftReference;
+import java.util.ArrayList;
+import java.util.Comparator;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
-import lucee.commons.collection.LongKeyList;
-import lucee.commons.io.log.Log;
-import lucee.commons.io.log.LogUtil;
-import lucee.runtime.config.Config;
+import lucee.commons.io.SystemUtil;
import lucee.runtime.dump.DumpData;
import lucee.runtime.dump.DumpProperties;
import lucee.runtime.dump.DumpTable;
import lucee.runtime.dump.DumpUtil;
import lucee.runtime.dump.Dumpable;
import lucee.runtime.dump.SimpleDumpData;
+import lucee.runtime.op.Caster;
import lucee.runtime.type.dt.DateTimeImpl;
/**
@@ -41,18 +43,20 @@
*/
public final class PageSourcePool implements Dumpable {
// TODO must not be thread safe, is used in sync block only
- private Map> pageSources = new ConcurrentHashMap>();
+ private final Map> pageSources = new ConcurrentHashMap>();
// timeout timeout for files
private long timeout;
// max size of the pool cache
- private int maxSize;
+ private int maxSize = 10000;
+ private int maxSize_min = 1000;
/**
* constructor of the class
*/
public PageSourcePool() {
this.timeout = 10000;
- this.maxSize = 1000;
+ this.maxSize = Caster.toIntValue(SystemUtil.getSystemPropOrEnvVar("lucee.pagePool.maxSize", null), maxSize);
+ maxSize_min = Math.max(this.maxSize - 1000, 1000);
}
/**
@@ -64,8 +68,12 @@ public PageSourcePool() {
*/
public PageSource getPageSource(String key, boolean updateAccesTime) { // DO NOT CHANGE INTERFACE (used by Argus Monitor)
SoftReference tmp = pageSources.get(key.toLowerCase());
- PageSource ps = tmp == null ? null : tmp.get();
- if (ps == null) return null;
+ if (tmp == null) return null;
+ PageSource ps = tmp.get();
+ if (ps == null) {
+ pageSources.remove(key.toLowerCase());
+ return null;
+ }
if (updateAccesTime) ps.setLastAccessTime();
return ps;
}
@@ -77,8 +85,10 @@ public PageSource getPageSource(String key, boolean updateAccesTime) { // DO NOT
* @param ps pagesource to store
*/
public void setPage(String key, PageSource ps) {
+ if (pageSources.size() > maxSize) {
+ cleanLoaders();
+ }
ps.setLastAccessTime();
-
pageSources.put(key.toLowerCase(), new SoftReference(ps));
}
@@ -101,23 +111,18 @@ public String[] keys() {
return set.toArray(new String[set.size()]);
}
- /**
- * removes a page from the page pool
- *
- * @param key key reference to page object
- * @return page object matching to key reference
- */
- /*
- * private boolean remove(String key) {
- *
- * if (pageSources.remove(key.toLowerCase()) != null) return true;
- *
- * Set set = pageSources.keySet(); String[] keys = set.toArray(new String[set.size()]); //
- * done this way to avoid ConcurrentModificationException SoftReference tmp; PageSource
- * ps; for (String k: keys) { tmp = pageSources.get(k); ps = tmp == null ? null : tmp.get(); if (ps
- * != null && key.equalsIgnoreCase(ps.getClassName())) { pageSources.remove(k); return true; } }
- * return false; }
- */
+ public List values(boolean loaded) {
+ List vals = new ArrayList<>();
+ if (pageSources == null) return vals;
+
+ PageSource ps;
+ for (SoftReference sr: pageSources.values()) {
+ ps = sr.get();
+ if (ps != null && (!loaded || ((PageSourceImpl) ps).isLoad())) vals.add(ps);
+
+ }
+ return vals;
+ }
public boolean flushPage(String key) {
SoftReference tmp = pageSources.get(key.toLowerCase());
@@ -142,45 +147,81 @@ public boolean flushPage(String key) {
* @return returns the size of the pool
*/
public int size() {
- return pageSources.size();
+ int size = 0;
+
+ for (Entry> entry: pageSources.entrySet()) {
+ if (entry.getValue().get() != null) size++;
+ else {
+ pageSources.remove(entry.getKey());
+ }
+ }
+ return size;
}
/**
* @return returns if pool is empty or not
*/
public boolean isEmpty() {
- return pageSources.isEmpty();
+ return size() > 0;
}
- /**
- * clear unused pages from page pool
- */
- public void clearUnused(Config config) {
- if (size() > maxSize) {
- LogUtil.log(config, Log.LEVEL_INFO, PageSourcePool.class.getName(), "PagePool size [" + size() + "] has exceeded max size [" + maxSize + "]. Clearing unused...");
- String[] keys = keys();
- LongKeyList list = new LongKeyList();
- for (int i = 0; i < keys.length; i++) {
- PageSource ps = getPageSource(keys[i], false);
- long updateTime = ps.getLastAccessTime();
- if (updateTime + timeout < System.currentTimeMillis()) {
- long add = ((ps.getAccessCount() - 1) * 10000);
- if (add > timeout) add = timeout;
- list.add(updateTime + add, keys[i]);
+ public void cleanLoaders() {
+ if (pageSources.size() < maxSize) return;
+ synchronized (pageSources) {
+ {
+ for (Entry> e: pageSources.entrySet()) {
+ if (e.getValue() == null || e.getValue().get() == null) pageSources.remove(e.getKey());
}
}
- while (size() > maxSize) {
- Object key = list.shift();
- if (key == null) break;
- // remove(key.toString());
+ if (pageSources.size() < maxSize) return;
+ ArrayList>> entryList = new ArrayList<>(pageSources.entrySet());
+
+ // Sort the list by the 'lastModified' timestamp in ascending order
+ entryList.sort(new Comparator>>() {
+
+ @Override
+ public int compare(Entry