Merge remote-tracking branch 'alfresco-remote-api/master'

This commit is contained in:
Chris Shields
2020-07-21 10:44:44 +01:00
2274 changed files with 296502 additions and 0 deletions

4
remote-api/.gitbugtraq Normal file
View File

@@ -0,0 +1,4 @@
# For SmartGit
[bugtraq "jira"]
url = https://issues.alfresco.com/jira/browse/%BUGID%
logRegex = ([A-Z]+-\\d+)

39
remote-api/.gitignore vendored Normal file
View File

@@ -0,0 +1,39 @@
*.class
# Eclipse
.classpath
.settings
.project
# Intellij
.idea/
*.iml
*.iws
# Mac
.DS_Store
# Maven
target
*.log
*.log.*
# Mobile Tools for Java (J2ME)
.mtj
.tmp/
# Package Files #
*.jar
*.war
*.ear
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
# Development
alf_data/
/src/main/resources/alfresco-global.properties
/src/main/resources/alfresco/extension/custom-log4j.properties

View File

@@ -0,0 +1,10 @@
<settings>
<!-- required to push artifacts to repositories -->
<servers>
<server>
<id>alfresco-public</id>
<username>${env.MAVEN_USERNAME}</username>
<password>${env.MAVEN_PASSWORD}</password>
</server>
</servers>
</settings>

65
remote-api/.travis.yml Normal file
View File

@@ -0,0 +1,65 @@
dist: xenial
sudo: required
language: java
jdk:
- openjdk11
services:
- docker
cache:
directories:
- $HOME/.m2
# the cache can grow constantly
before_cache:
- rm -rf $HOME/.m2/repository/org/alfresco/alfresco-remote-api
- rm -rf $HOME/.m2/repository/org/alfresco/alfresco-repository
branches:
only:
- master
- /support\/.*/
- /feature\/.*/
stages:
- test
- release
before_install:
- docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:11.7 postgres -c 'max_connections=300'
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.15.8
install: travis_retry mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V
jobs:
include:
- stage: test
name: "WhiteSource scan"
# only on support branches or master and if it is not a PR
if: fork = false AND (branch = master OR branch =~ /support\/SP\/.*/) AND type != pull_request
script:
# Download the latest version of WhiteSource Unified Agent
- curl -LJO https://github.com/whitesource/unified-agent-distribution/releases/latest/download/wss-unified-agent.jar
# Run WhiteSource Unified Agent
- java -jar wss-unified-agent.jar -apiKey ${WHITESOURCE_API_KEY} -c .wss-unified-agent.config
- name: "AppContext01TestSuite"
script: travis_wait 20 mvn test -B -Dtest=AppContext01TestSuite -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
- name: "AppContext02TestSuite"
script: travis_wait 20 mvn test -B -Dtest=AppContext02TestSuite -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
- name: "AppContext03TestSuite"
script: travis_wait 20 mvn test -B -Dtest=AppContext03TestSuite -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
- name: "AppContext04TestSuite"
script: travis_wait 20 mvn test -B -Dtest=AppContext04TestSuite -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
- name: "AppContextExtraTestSuite"
script: travis_wait 20 mvn test -B -Dtest=AppContextExtraTestSuite -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
- stage: release
name: "Push to Nexus"
if: fork = false AND (branch = master OR branch =~ /support\/.*/) AND type != pull_request AND commit_message !~ /\[no-release\]/
before_install:
- "cp .travis.settings.xml $HOME/.m2/settings.xml"
script:
# Use full history for release
- git checkout -B "${TRAVIS_BRANCH}"
# Add email to link commits to user
- git config user.email "${GIT_EMAIL}"
# Skip building of release commits
- mvn --batch-mode -DscmCommentPrefix="[maven-release-plugin][skip ci] " -Dusername="${GIT_USERNAME}" -Dpassword="${GIT_PASSWORD}" -DskipTests -Darguments=-DskipTests release:clean release:prepare release:perform

8
remote-api/.whitesource Normal file
View File

@@ -0,0 +1,8 @@
{
"generalSettings": {
"shouldScanRepo": true
},
"checkRunSettings": {
"vulnerableCheckRunConclusionLevel": "failure"
}
}

View File

@@ -0,0 +1,228 @@
####################################################################
# WhiteSource Unified-Agent configuration file
####################################################################
##########################################
# GENERAL SCAN MODE: Files and Package Managers
##########################################
checkPolicies=true
forceCheckAllDependencies=true
forceUpdate=true
forceUpdate.failBuildOnPolicyViolation=true
offline=false
#ignoreSourceFiles=true
#scanComment=
#updateInventory=false
#resolveAllDependencies=false
#failErrorLevel=ALL
#requireKnownSha1=false
#generateScanReport=true
#scanReportTimeoutMinutes=10
#excludeDependenciesFromNodes=.*commons-io.*,.*maven-model
#projectPerFolder=true
#projectPerFolderIncludes=
#projectPerFolderExcludes=
#wss.connectionTimeoutMinutes=60
# Change the below URL to your WhiteSource server.
# Use the 'WhiteSource Server URL' which can be retrieved
# from your 'Profile' page on the 'Server URLs' panel.
# Then, add the '/agent' path to it.
wss.url=https://saas.whitesourcesoftware.com/agent
#npm.resolveDependencies=false
#npm.ignoreSourceFiles=false
#npm.includeDevDependencies=true
#npm.runPreStep=true
#npm.ignoreNpmLsErrors=true
#npm.ignoreScripts=true
#npm.yarnProject=true
#npm.accessToken=
#npm.identifyByNameAndVersion=true
#bower.resolveDependencies=false
#bower.ignoreSourceFiles=true
#bower.runPreStep=true
#nuget.resolvePackagesConfigFiles=false
#nuget.resolveCsProjFiles=false
#nuget.resolveDependencies=false
#nuget.restoreDependencies=true
#nuget.ignoreSourceFiles=true
#nuget.runPreStep=true
#nuget.resolveNuspecFiles=false
#python.resolveDependencies=false
#python.ignoreSourceFiles=false
#python.ignorePipInstallErrors=true
#python.installVirtualenv=true
#python.resolveHierarchyTree=false
#python.requirementsFileIncludes=requirements.txt
#python.resolveSetupPyFiles=true
#python.runPipenvPreStep=true
#python.pipenvDevDependencies=true
#python.IgnorePipenvInstallErrors=true
#maven.ignoredScopes=test provided
maven.resolveDependencies=true
#maven.ignoreSourceFiles=true
#maven.aggregateModules=true
maven.ignorePomModules=false
#maven.runPreStep=true
#maven.ignoreMvnTreeErrors=true
#maven.environmentPath=
#maven.m2RepositoryPath=
#gradle.ignoredScopes=
#gradle.resolveDependencies=false
#gradle.runAssembleCommand=false
#gradle.runPreStep=true
#gradle.ignoreSourceFiles=true
#gradle.aggregateModules=true
#gradle.preferredEnvironment=wrapper
#gradle.localRepositoryPath=
#paket.resolveDependencies=false
#paket.ignoredGroups=
#paket.ignoreSourceFiles=false
#paket.runPreStep=true
#paket.exePath=
#go.resolveDependencies=false
#go.collectDependenciesAtRuntime=true
#go.dependencyManager=
#go.ignoreSourceFiles=true
#go.glide.ignoreTestPackages=false
#go.gogradle.enableTaskAlias=true
#ruby.resolveDependencies = false
#ruby.ignoreSourceFiles = false
#ruby.installMissingGems = true
#ruby.runBundleInstall = true
#ruby.overwriteGemFile = true
#sbt.resolveDependencies=false
#sbt.ignoreSourceFiles=true
#sbt.aggregateModules=true
#sbt.runPreStep=true
#sbt.targetFolder=
#php.resolveDependencies=false
#php.runPreStep=true
#php.includeDevDependencies=true
#html.resolveDependencies=false
#cocoapods.resolveDependencies=false
#cocoapods.runPreStep=true
#cocoapods.ignoreSourceFiles=false
#hex.resolveDependencies=false
#hex.runPreStep=true
#hex.ignoreSourceFiles=false
#hex.aggregateModules=true
##################################
# Organization tokens:
##################################
apiKey=
#userKey is required if WhiteSource administrator has enabled "Enforce user level access" option
#userKey=
projectName=alfresco-remote-api
projectVersion=
projectToken=
productName=ACS Community
productVersion=
productToken=
#updateType=APPEND
#requesterEmail=user@provider.com
#########################################################################################
# Includes/Excludes Glob patterns - PLEASE USE ONLY ONE EXCLUDE LINE AND ONE INCLUDE LINE
#########################################################################################
#includes=**/*.c **/*.cc **/*.cp **/*.cpp **/*.cxx **/*.c++ **/*.h **/*.hpp **/*.hxx
#includes=**/*.m **/*.mm **/*.js **/*.php
includes=**/*.jar
#includes=**/*.gem **/*.rb
#includes=**/*.dll **/*.cs **/*.nupkg
#includes=**/*.tgz **/*.deb **/*.gzip **/*.rpm **/*.tar.bz2
#includes=**/*.zip **/*.tar.gz **/*.egg **/*.whl **/*.py
## Exclude file extensions or specific directories by adding **/*.<extension> or **<excluded_dir>/**
excludes=**/*sources.jar **/*javadoc.jar
case.sensitive.glob=false
followSymbolicLinks=true
##################################
# Archive properties
##################################
#archiveExtractionDepth=2
#archiveIncludes=**/*.war **/*.ear
#archiveExcludes=**/*sources.jar
##################################
# Proxy settings
##################################
#proxy.host=
#proxy.port=
#proxy.user=
#proxy.pass=
##################################
# SCM settings
##################################
#scm.type=
#scm.user=
#scm.pass=
#scm.ppk=
#scm.url=
#scm.branch=
#scm.tag=
#scm.npmInstall=
#scm.npmInstallTimeoutMinutes=
#scm.repositoriesFile=
##############################################
# SCAN MODE: Linux package manager settings
##############################################
#scanPackageManager=true
##################################
# SCAN MODE: Docker images
##################################
#docker.scanImages=true
#docker.includes=.*.*
#docker.excludes=
#docker.pull.enable=true
#docker.pull.images=.*.*
#docker.pull.maxImages=10
#docker.pull.tags=.*.*
#docker.pull.digest=
#docker.delete.force=true
#docker.login.sudo=false
#docker.aws.enable=true
#docker.aws.registryIds=
##################################
# SCAN MODE: Docker containers
##################################
#docker.scanContainers=true
#docker.containerIncludes=.*.*
#docker.containerExcludes=
################################
# Serverless settings
################################
#serverless.provider=
#serverless.scanFunctions=true
#serverless.includes=
#serverless.excludes=
#serverless.region=
#serverless.maxFunctions=10

View File

@@ -0,0 +1,16 @@
### Contributing
Thanks for your interest in contributing to this project!
The following is a set of guidelines for contributing to this library. Most of them will make the life of the reviewer easier and therefore decrease the time required for the patch be included in the next version.
Because this project forms a part of Alfresco Content Services, the guidelines are hosted in the [Alfresco Social Community](http://community.alfresco.com/community/ecm) where they can be referenced from multiple projects.
Read an [overview on how this project is goverened](https://community.alfresco.com/docs/DOC-6385-project-overview-repository).
You can report an issue in the ALF project of the [Alfresco issue tracker](http://issues.alfresco.com).
Read [instructions for a good issue report](https://community.alfresco.com/docs/DOC-6263-reporting-an-issue).
Read [instructions for making a contribution](https://community.alfresco.com/docs/DOC-6269-submitting-contributions).
Please follow [the coding standards](https://community.alfresco.com/docs/DOC-4658-coding-standards).

165
remote-api/LICENSE Normal file
View File

@@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

41
remote-api/README.md Normal file
View File

@@ -0,0 +1,41 @@
### Alfresco Remote API
[![Build Status](https://travis-ci.com/Alfresco/alfresco-remote-api.svg?branch=master)](https://travis-ci.com/Alfresco/alfresco-remote-api)
Remote API is a library packaged as a jar file which is part of [Alfresco Content Services Repository](https://community.alfresco.com/docs/DOC-6385-project-overview-repository).
The library contains the following:
* REST API framework
* WebScript implementations including [V1 REST APIs](https://community.alfresco.com/community/ecm/blog/2017/05/02/v1-rest-api-10-things-you-should-know)
* [OpenCMIS](https://chemistry.apache.org/java/opencmis.html) implementations
### Building and testing
The project can be built by running Maven command:
~~~
mvn clean install
~~~
The tests are combined in test classes split by test type or Spring application context used in the test, see classes in _src/test/java/org/alfresco_. All of these classes as well as individual tests can be run by specifying the test class name and a set of DB connection properties, for example:
~~~
mvn clean test -Dtest=SomeTest -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql:alfresco -Ddb.username=alfresco -Ddb.password=alfresco
~~~
### Artifacts
The artifacts can be obtained by:
* downloading from [Alfresco repository](https://artifacts.alfresco.com/nexus/content/groups/public)
* getting as Maven dependency by adding the dependency to your pom file:
~~~
<dependency>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-remote-api</artifactId>
<version>version</version>
</dependency>
~~~
and Alfresco Maven repository:
~~~
<repository>
<id>alfresco-maven-repo</id>
<url>https://artifacts.alfresco.com/nexus/content/groups/public</url>
</repository>
~~~
The SNAPSHOT version of the artifact is **never** published.
### Contributing guide
Please use [this guide](CONTRIBUTING.md) to make a contribution to the project.

View File

@@ -0,0 +1,8 @@
# Branch specific configuration file for localisation scripts
MESSAGE_SEARCH_PATH="src/main/resources/alfresco/messages/admin-console*.properties src/main/resources/alfresco/messages/custommodel-restapi-messages*.properties src/main/resources/alfresco/messages/rest-framework-messages*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/admin/admin-communitysummary.get*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/admin/consoles/admin-repoconsole.get*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/admin/consoles/admin-tenantconsole.get*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/admin/consoles/admin-workflowconsole.get*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/admin/support-tools/admin-nodebrowser.get*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/audit/entry*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/blogs/post/blog-post.delete*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/discussions/posts/forum-post.delete*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/links/links-delete.post*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/links/links.post*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/links/links.put*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/person/user-csv-upload.post*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/slingshot/calendar/event.get*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/slingshot/calendar/event.post*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/slingshot/calendar/event.put*.properties"
EXCLUDED_FILES="src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/audit/control.properties"

618
remote-api/pom.xml Normal file
View File

@@ -0,0 +1,618 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>alfresco-remote-api</artifactId>
<name>Alfresco Remote API</name>
<version>8.213-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-super-pom</artifactId>
<version>12</version>
</parent>
<scm>
<connection>scm:git:https://github.com/Alfresco/alfresco-remote-api.git</connection>
<developerConnection>scm:git:https://github.com/Alfresco/alfresco-remote-api.git</developerConnection>
<url>https://github.com/Alfresco/alfresco-remote-api</url>
<tag>HEAD</tag>
</scm>
<distributionManagement>
<repository>
<id>alfresco-public</id>
<url>https://artifacts.alfresco.com/nexus/content/repositories/releases</url>
</repository>
<snapshotRepository>
<id>alfresco-public</id>
<url>https://artifacts.alfresco.com/nexus/content/repositories/snapshots</url>
</snapshotRepository>
</distributionManagement>
<properties>
<licenseName>community</licenseName>
<maven.build.sourceVersion>11</maven.build.sourceVersion>
<dir.root>${project.build.directory}/alf_data</dir.root>
<img.exe>convert</img.exe>
<dependency.alfresco-repository.version>8.243</dependency.alfresco-repository.version>
<dependency.alfresco-data-model.version>8.135</dependency.alfresco-data-model.version>
<dependency.alfresco-core.version>8.37</dependency.alfresco-core.version>
<dependency.alfresco-pdf-renderer.version>1.1</dependency.alfresco-pdf-renderer.version>
<dependency.jackson.version>2.11.1</dependency.jackson.version>
<dependency.jackson-databind.version>2.10.1</dependency.jackson-databind.version>
<dependency.webscripts.version>8.5</dependency.webscripts.version>
<dependency.opencmis.version>1.0.0</dependency.opencmis.version>
<dependency.spring.version>5.2.7.RELEASE</dependency.spring.version>
<dependency.postgresql.version>42.2.14</dependency.postgresql.version>
<dependency.cxf.version>3.3.7</dependency.cxf.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- Newer cxf libs, see REPO-3131 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>${dependency.cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
<version>${dependency.cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-client</artifactId>
<version>${dependency.cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>${dependency.cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-ws-policy</artifactId>
<version>${dependency.cxf.version}</version>
</dependency>
<!-- upgrade dependency from TIKA -->
<dependency>
<groupId>com.github.junrar</groupId>
<artifactId>junrar</artifactId>
<version>4.0.0</version>
</dependency>
<!-- upgrade dependency from TIKA -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.13.1</version>
</dependency>
<!-- update dependency from opencmis-extension -->
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1-HTTPCLIENT-1265</version>
</dependency>
<!-- newer dependency from camel-jackson -->
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-jaxb-annotations</artifactId>
<version>${dependency.jackson.version}</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.12</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.13</version>
</dependency>
<!-- REPO-4986, REPO-4987 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>${dependency.spring.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-repository</artifactId>
<version>${dependency.alfresco-repository.version}</version>
</dependency>
<dependency>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-data-model</artifactId>
<version>${dependency.alfresco-data-model.version}</version>
<exclusions>
<!-- Duplicate classes from com.sun.activation:jakarta.activation-->
<exclusion>
<groupId>com.sun.activation</groupId>
<artifactId>javax.activation</artifactId>
</exclusion>
<!-- REPO-4998 - Exclusion due to classpath conflicts between org.codehaus.woodstox:woodstox-core-asl and com.fasterxml.woodstox:woodstox-core -->
<exclusion>
<groupId>org.codehaus.woodstox</groupId>
<artifactId>woodstox-core-asl</artifactId>
</exclusion>
<!-- Duplicate classes from jakarta.annotation:jakarta.annotation-api-->
<exclusion>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
</exclusion>
<!-- REPO-5009 Excluded to avoid duplicated classes with javax.jws:javax.jws-api -->
<exclusion>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-ws-metadata_2.0_spec</artifactId>
</exclusion>
<!-- Duplicates classes from jakarta.transaction:jakarta.transaction-api -->
<exclusion>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-jta_1.1_spec</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${dependency.jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${dependency.jackson-databind.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${dependency.jackson.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-csv</artifactId>
<version>1.8</version>
</dependency>
<dependency>
<groupId>org.apache.santuario</groupId>
<artifactId>xmlsec</artifactId>
<version>1.5.8</version>
</dependency>
<!-- newer version, see REPO-3133 -->
<dependency>
<groupId>org.alfresco.surf</groupId>
<artifactId>spring-webscripts</artifactId>
<version>${dependency.webscripts.version}</version>
</dependency>
<dependency>
<groupId>javax.xml</groupId>
<artifactId>jaxrpc-api</artifactId>
<version>1.1</version>
</dependency>
<!-- This is needed at runtime by Web Client, so not really a test dependency -->
<dependency>
<groupId>org.apache.chemistry.opencmis</groupId>
<artifactId>chemistry-opencmis-test-tck</artifactId>
<version>${dependency.opencmis.version}</version>
<exclusions>
<!-- Duplicate classes from com.sun.activation:jakarta.activation-->
<exclusion>
<groupId>com.sun.activation</groupId>
<artifactId>javax.activation</artifactId>
</exclusion>
<!-- REPO-5009 Excluded to avoid duplicated classes with javax.jws:javax.jws-api -->
<exclusion>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-ws-metadata_2.0_spec</artifactId>
</exclusion>
<!-- Duplicates classes from jakarta.transaction:jakarta.transaction-api -->
<exclusion>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-jta_1.1_spec</artifactId>
</exclusion>
</exclusions>
<!-- <scope>test</scope> -->
</dependency>
<!-- the cxf libs were updated, see dependencyManagement section -->
<!-- Test dependencies -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.4.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${dependency.spring.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-repository</artifactId>
<version>${dependency.alfresco-repository.version}</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-core</artifactId>
<version>${dependency.alfresco-core.version}</version>
<classifier>tests</classifier>
<scope>test</scope>
<exclusions>
<!-- Duplicates classes from jakarta.transaction:jakarta.transaction-api -->
<exclusion>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
</exclusion>
<!-- Duplicates classes from jakarta.xml.bind:jakarta.xml.bind-api -->
<exclusion>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.alfresco.surf</groupId>
<artifactId>spring-webscripts</artifactId>
<version>${dependency.webscripts.version}</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>${dependency.postgresql.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>8.2.0.v20160908</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.eclipse.jetty.orbit</groupId>
<artifactId>javax.servlet</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-security</artifactId>
<version>8.2.0.v20160908</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<version>8.2.0.v20160908</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.alfresco.cmis.client</groupId>
<artifactId>alfresco-opencmis-extension</artifactId>
<version>2.0</version>
<scope>test</scope>
<exclusions>
<!-- REPO-5009 Excluded to avoid duplicated classes with javax.jws:javax.jws-api -->
<exclusion>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-ws-metadata_2.0_spec</artifactId>
</exclusion>
<!-- MNT-20557: Excluding javax.annotation:javax.annotation-api, jakarta.annotation:jakarta.annotation-api will be used instead -->
<exclusion>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<profiles>
<!-- Profiles to extract the alfresco-pdf-renderer -->
<profile>
<id>win-alfresco-pdf-renderer-test</id>
<activation>
<os>
<family>windows</family>
</os>
</activation>
<dependencies>
<dependency>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-pdf-renderer</artifactId>
<version>${dependency.alfresco-pdf-renderer.version}</version>
<classifier>win64</classifier>
<type>tgz</type>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<inherited>false</inherited>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>extract-alfresco-pdf-renderer-test</id>
<phase>generate-test-resources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<skip>${skipTests}</skip>
<target>
<echo message="Extracting alfresco-pdf-renderer (windows) for testing..." />
<mkdir dir="${project.build.directory}/test-binaries/alfresco-pdf-renderer" />
<untar compression="gzip" src="${settings.localRepository}/org/alfresco/alfresco-pdf-renderer/${dependency.alfresco-pdf-renderer.version}/alfresco-pdf-renderer-${dependency.alfresco-pdf-renderer.version}-win64.tgz" dest="${project.build.directory}/test-binaries/alfresco-pdf-renderer" />
</target>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<properties>
<alfresco-pdf-renderer.exe>${project.build.directory}/test-binaries/alfresco-pdf-renderer/alfresco-pdf-renderer</alfresco-pdf-renderer.exe>
</properties>
</profile>
<profile>
<id>linux-alfresco-pdf-renderer-test</id>
<activation>
<os>
<family>linux</family>
</os>
</activation>
<dependencies>
<dependency>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-pdf-renderer</artifactId>
<version>${dependency.alfresco-pdf-renderer.version}</version>
<classifier>linux</classifier>
<type>tgz</type>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<inherited>false</inherited>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>extract-alfresco-pdf-renderer-test</id>
<phase>generate-test-resources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<skip>${skipTests}</skip>
<target>
<echo message="Extracting alfresco-pdf-renderer (linux) for testing..." />
<mkdir dir="${project.build.directory}/test-binaries/alfresco-pdf-renderer" />
<exec failonerror="true" executable="tar" dir="${project.build.directory}/test-binaries/alfresco-pdf-renderer">
<arg value="xf" />
<arg value="${settings.localRepository}/org/alfresco/alfresco-pdf-renderer/${dependency.alfresco-pdf-renderer.version}/alfresco-pdf-renderer-${dependency.alfresco-pdf-renderer.version}-linux.tgz" />
</exec>
</target>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<properties>
<alfresco-pdf-renderer.exe>${project.build.directory}/test-binaries/alfresco-pdf-renderer/alfresco-pdf-renderer</alfresco-pdf-renderer.exe>
</properties>
</profile>
<profile>
<id>osx-alfresco-pdf-renderer-test</id>
<activation>
<os>
<family>mac</family>
</os>
</activation>
<dependencies>
<dependency>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-pdf-renderer</artifactId>
<version>${dependency.alfresco-pdf-renderer.version}</version>
<classifier>osx</classifier>
<type>tgz</type>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<inherited>false</inherited>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>extract-alfresco-pdf-renderer-test</id>
<phase>generate-test-resources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<skip>${skipTests}</skip>
<target>
<echo message="Extracting alfresco-pdf-renderer (OS-X) for testing..." />
<mkdir dir="${project.build.directory}/test-binaries/alfresco-pdf-renderer" />
<exec failonerror="true" executable="tar" dir="${project.build.directory}/test-binaries/alfresco-pdf-renderer">
<arg value="xf" />
<arg value="${settings.localRepository}/org/alfresco/alfresco-pdf-renderer/${dependency.alfresco-pdf-renderer.version}/alfresco-pdf-renderer-${dependency.alfresco-pdf-renderer.version}-osx.tgz" />
</exec>
</target>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<properties>
<alfresco-pdf-renderer.exe>${project.build.directory}/test-binaries/alfresco-pdf-renderer/alfresco-pdf-renderer</alfresco-pdf-renderer.exe>
</properties>
</profile>
</profiles>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>license-maven-plugin</artifactId>
<version>2.0.0</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<!-- Create a jar of test classes -->
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<id>create-test-jar</id>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<id>default-test</id>
<configuration>
<!-- To prevent tests alfresco.log to be created in project roots and bother while synchronizing with SCM -->
<workingDirectory>${project.build.directory}</workingDirectory>
<systemPropertyVariables>
<alfresco-pdf-renderer.exe>${alfresco-pdf-renderer.exe}</alfresco-pdf-renderer.exe>
<!-- Database related properties -->
<db.url>${db.url}</db.url>
<db.driver>${db.driver}</db.driver>
<db.name>${db.name}</db.name>
<db.username>${db.username}</db.username>
<db.password>${db.password}</db.password>
<dir.root>${dir.root}</dir.root>
<img.exe>${img.exe}</img.exe>
<!-- BDE-91 -->
<alfresco.rmi.services.retries>30</alfresco.rmi.services.retries>
<alfresco.rmi.services.retryInterval>2000</alfresco.rmi.services.retryInterval>
<!-- FTR used in TransferWebScriptTest -->
<transferservice.receiver.enabled>true</transferservice.receiver.enabled>
</systemPropertyVariables>
</configuration>
</execution>
</executions>
</plugin>
<!-- We still use committed generated sources -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>src/main/generated</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
<!-- ACE-3329 Create _en.properties message files -->
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>duplicate-english-messages</id>
<phase>generate-resources</phase>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
<configuration>
<target>
<copy todir="${project.build.outputDirectory}">
<fileset dir="${basedir}/src/main/resources" includes="alfresco/messages/**/*.properties,alfresco/templates/webscripts/**/*.properties" />
<mapper type="regexp" from="^([^_]*).properties$" to="\1_en.properties" />
</copy>
</target>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>license-maven-plugin</artifactId>
<configuration>
<addJavaLicenseAfterPackage>false</addJavaLicenseAfterPackage>
<organizationName>Alfresco Software Limited</organizationName>
<failOnMissingHeader>true</failOnMissingHeader>
<failOnNotUptodateHeader>true</failOnNotUptodateHeader>
<licenseResolver>classpath://alfresco</licenseResolver>
<licenseName>${licenseName}</licenseName>
<roots>
<root>src</root>
</roots>
<includes>
<include>**/*.java</include>
<include>**/*.jsp</include>
</includes>
</configuration>
<executions>
<execution>
<id>check-licenses</id>
<phase>compile</phase>
<goals>
<goal>check-file-header</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-license-headers</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,154 @@
grammar WhereClause;
options
{
// antlr will generate java lexer and parser
language = Java;
// generated parser should create abstract syntax tree
output = AST;
}
//package, we have to add package declaration on top of it
@lexer::header {
package org.alfresco.rest.antlr;
import java.util.Map;
import java.util.HashMap;
import org.alfresco.rest.framework.resource.parameters.where.InvalidQueryException;
import org.alfresco.rest.framework.resource.parameters.where.WhereCompiler;
}
@lexer::members {
@Override
public void recover(RecognitionException e)
{
throw new InvalidQueryException(WhereCompiler.resolveMessage(e));
}
}
//package, we have to add package declaration on top of it
@parser::header {
package org.alfresco.rest.antlr;
import org.alfresco.rest.framework.resource.parameters.where.InvalidQueryException;
}
@parser::members {
// These methods are here to force the parser to error instead of suppressing problems.
// @Override
// public void reportError(RecognitionException e) {
// System.out.println("CUSTOM ERROR...\n" + e);
// throw new InvalidQueryException(e.getMessage());
// }
@Override
protected Object recoverFromMismatchedToken(IntStream input, int ttype, BitSet follow) throws RecognitionException
{
throw new MismatchedTokenException(ttype, input);
}
@Override
public Object recoverFromMismatchedSet(IntStream input, RecognitionException e, BitSet follow) throws RecognitionException
{
throw e;
}
//
// @Override
// public String getErrorMessage(RecognitionException e, String[] tokenNames)
// {
// System.out.println("THROW ME...\n" + e);
// throw new InvalidQueryException(e.getMessage());
// }
// End of methods here to force the parser to error instead of supressing problems.
}
@rulecatch
{
catch(RecognitionException e)
{
throw e;
}
}
// ***************** lexer rules:
NEGATION: ('not'|'NOT')WS;
EXISTS: 'exists'|'EXISTS';
IN: WS('in'|'IN');
MATCHES: WS('matches'|'MATCHES');
BETWEEN: WS('between'|'BETWEEN');
OR: WS('or'|'OR')WS;
AND: WS('and'|'AND')WS;
EQUALS: WS?'='WS?;
LESSTHAN: WS?'<'WS?;
GREATERTHAN: WS?'>'WS?;
LESSTHANOREQUALS: WS?'<='WS?;
GREATERTHANOREQUALS: WS?'>='WS?;
LEFTPAREN: '(';
RIGHTPAREN: ')';
COMMA: ',';
COLON: ':';
SINGLEQUOTE: '\'';
PROPERTYVALUE: (SINGLEQUOTE (~SINGLEQUOTE|'\\'SINGLEQUOTE)* SINGLEQUOTE) |IDENTIFIERDIGIT+;
PROPERTYNAME: '/'? IDENTIFIER ('/'IDENTIFIER)*;
fragment IDENTIFIERLETTERORDIGIT: (IDENTIFIERLETTER | IDENTIFIERDIGIT);
fragment IDENTIFIER : (IDENTIFIERLETTER (IDENTIFIERLETTERORDIGIT* | (IDENTIFIERLETTERORDIGIT* COLON IDENTIFIERLETTERORDIGIT*)));
WS : ( ' ' | '\t' | '\r' | '\n' )+ { $channel = HIDDEN; };
fragment IDENTIFIERLETTER // any Unicode character that is a Java letter (see below)
: '\u0041'..'\u005a' // A-Z
| '\u005f' // _
| '\u0061'..'\u007a' // a-z
| '\u00c0'..'\u00d6' // À-Ö
| '\u00d8'..'\u00f6' // Ø-ö
| '\u00f8'..'\u00ff' // ø-ÿ
| '\u0100'..'\u1fff'
| '\u3040'..'\u318f'
| '\u3300'..'\u337f'
| '\u3400'..'\u3d2d'
| '\u4e00'..'\u9fff'
| '\uf900'..'\ufaff'
;
fragment IDENTIFIERDIGIT
: '\u0030'..'\u0039' // 0-9
| '\u0660'..'\u0669' // Arabic 0-9
| '\u06f0'..'\u06f9' // Arabic-Indic 0-9
| '\u0966'..'\u096f' // Devanagari 0-9
| '\u09e6'..'\u09ef' // Bengali 0-9
| '\u0a66'..'\u0a6f' // Gurmukhi 0-9
| '\u0ae6'..'\u0aef' // Gujarati 0-9
| '\u0b66'..'\u0b6f' // Oriya 0-9
| '\u0be7'..'\u0bef' // Tamil 0-9
| '\u0c66'..'\u0c6f' // Telugu 0-9
| '\u0ce6'..'\u0cef' // Kannada 0-9
| '\u0d66'..'\u0d6f' // Malayalam 0-9
| '\u0e50'..'\u0e59' // Thai 0-9
| '\u0ed0'..'\u0ed9' // Lao 0-9
| '\u1040'..'\u1049' // Myanmar 0-9
;
// ***************** parser rules:
whereclause : WS? LEFTPAREN! WS? predicate RIGHTPAREN! WS?;
predicate : simplepredicate
| simplepredicate (AND simplepredicate)+ -> ^(AND simplepredicate+)
| simplepredicate (OR simplepredicate)+ -> ^(OR simplepredicate+);
simplepredicate : allowedpredicates -> allowedpredicates
| NEGATION allowedpredicates -> ^(NEGATION allowedpredicates);
allowedpredicates : comparisonpredicate | existspredicate | betweenpredicate | inpredicate | matchespredicate;
comparisonpredicate: PROPERTYNAME comparisonoperator value -> ^(comparisonoperator PROPERTYNAME value);
comparisonoperator: EQUALS|LESSTHAN|GREATERTHAN|LESSTHANOREQUALS|GREATERTHANOREQUALS;
existspredicate: EXISTS LEFTPAREN WS? PROPERTYNAME RIGHTPAREN -> ^(EXISTS PROPERTYNAME);
betweenpredicate: PROPERTYNAME BETWEEN LEFTPAREN WS? propertyvaluepair RIGHTPAREN -> ^(BETWEEN PROPERTYNAME propertyvaluepair);
inpredicate: PROPERTYNAME IN LEFTPAREN WS? propertyvaluelist RIGHTPAREN -> ^(IN PROPERTYNAME propertyvaluelist);
matchespredicate: PROPERTYNAME MATCHES LEFTPAREN WS? value RIGHTPAREN -> ^(MATCHES PROPERTYNAME value);
propertyvaluepair: value COMMA value -> value+;
propertyvaluelist: value (COMMA value)* -> value+;
value: a=PROPERTYVALUE -> ^(PROPERTYVALUE[$a] )
| b=PROPERTYNAME -> ^(PROPERTYVALUE[$b] ); //rewrite this a propertyvalue
selectClause: PROPERTYNAME (COMMA PROPERTYNAME)* -> PROPERTYNAME+;
// ****
// SOME NOTES
// () - Parentheses. Used to group several elements, so they are treated as one single token
// ? - Any token followed by ? occurs 0 or 1 times
// * - Any token followed by * can occur 0 or more times
// + - Any token followed by + can occur 1 or more times
// . - Any character/token can occur one time
// ~ - Any character/token following the ~ may not occur at the current place
// .. - Between two characters .. spans a range which accepts every character between both boundaries inclusive
// ****

View File

@@ -0,0 +1,33 @@
AppClientTest is a tool for testing an AtomPub Service.
http://code.google.com/p/feedvalidator/wiki/AppClientTest
1) To install and test installation...
$ svn co http://feedvalidator.googlecode.com/svn/trunk/apptestsuite/client/validator/ validator
$ python validator/appclienttest.py --output=results.html "http://bitworking.org/projects/apptestsite/app.cgi/service/;service_document"
$ firefox results.html
The above has been encapsulated in...
/projects/remote-api/source/test/apptest/install.sh
2) To execute appclienttest against Alfresco
/projects/remote-api/source/test/apptest/test.sh
3) Note: appclienttest.py arguments...
-h, --help show this help message and exit
--credentials=FILE FILE that contains a name and password on separate lines
with an optional third line with the authentication type
of 'ClientLogin <service>'.
--output=FILE FILE to store test results
--verbose Print extra information while running.
--quiet Do not print anything while running.
--debug Print low level HTTP information while running.
--html Output is formatted in HTML
--record=DIR Record all the responses to be used later in playback
mode.
--playback=DIR Playback responses stored from a previous run.

View File

@@ -0,0 +1,2 @@
admin
admin

View File

@@ -0,0 +1,5 @@
# ! /bin/sh
svn co http://feedvalidator.googlecode.com/svn/trunk/apptestsuite/client/validator/ validator
python validator/appclienttest.py --html --verbose --output=results.html "http://bitworking.org/projects/apptestsite/app.cgi/service/;service_document"
open results.html

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,4 @@
# ! /bin/sh
python validator/appclienttest.py --html --credentials=credentials.txt --verbose --output=results.html "http://localhost:8080/alfresco/service/api/repository"
open results.html

View File

@@ -0,0 +1,24 @@
AND=4
BETWEEN=5
COLON=6
COMMA=7
EQUALS=8
EXISTS=9
GREATERTHAN=10
GREATERTHANOREQUALS=11
IDENTIFIER=12
IDENTIFIERDIGIT=13
IDENTIFIERLETTER=14
IDENTIFIERLETTERORDIGIT=15
IN=16
LEFTPAREN=17
LESSTHAN=18
LESSTHANOREQUALS=19
MATCHES=20
NEGATION=21
OR=22
PROPERTYNAME=23
PROPERTYVALUE=24
RIGHTPAREN=25
SINGLEQUOTE=26
WS=27

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,139 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2018 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.heartbeat;
import org.alfresco.heartbeat.datasender.HBData;
import org.alfresco.heartbeat.jobs.HeartBeatJobScheduler;
import org.alfresco.repo.descriptor.DescriptorDAO;
import org.alfresco.repo.thumbnail.ThumbnailDefinition;
import org.alfresco.util.PropertyCheck;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
* This class collects rendition request counts for HeartBeat. A rendition (such as "doclib") is always to the same
* target mimetype, but there may be different source mimetypes. As a result that may be multiple sets of data with
* the same rendition. It is also likely there will be multiple renditions reported in the same batch of data.
* <ul>
* <li>Collector ID: <b>acs.repository.renditions</b></li>
* <li>Data:
* <ul>
* <li><b>rendition:</b> String - The name of the rendition.</li>
* <li><b>count:</b> Integer - The number of times a rendition and sourceMimetype combination has been requested.</li>
* <li><b>sourceMimetype:</b> String - The source mimetype for the rendition.</li>
* <li><b>targetMimetype:</b> String - The target mimetype for the rendition.</li>
* </ul>
* </li>
* </ul>
*
* @author adavis
*/
public class RenditionsDataCollector extends HBBaseDataCollector implements InitializingBean
{
private static final Log logger = LogFactory.getLog(RenditionsDataCollector.class);
private DescriptorDAO currentRepoDescriptorDAO;
// Map keyed on rendition id to a Map keyed on source mimetypes to a count of the number of times it has been requested.
private final Map<ThumbnailDefinition, Map<String, AtomicInteger>> renditionRequests = new ConcurrentHashMap<>();
public RenditionsDataCollector(String collectorId, String collectorVersion, String cronExpression,
HeartBeatJobScheduler hbJobScheduler)
{
super(collectorId, collectorVersion, cronExpression, hbJobScheduler);
}
public void setCurrentRepoDescriptorDAO(DescriptorDAO currentRepoDescriptorDAO)
{
this.currentRepoDescriptorDAO = currentRepoDescriptorDAO;
}
@Override
public void afterPropertiesSet() throws Exception
{
PropertyCheck.mandatory(this, "currentRepoDescriptorDAO", currentRepoDescriptorDAO);
}
public void recordRenditionRequest(ThumbnailDefinition rendition, String sourceMimetype)
{
// Increment the count of renditions. Atomically creates missing parts of the Map structures.
renditionRequests.computeIfAbsent(rendition,
k -> new ConcurrentHashMap<>()).computeIfAbsent(sourceMimetype,
k -> new AtomicInteger()).incrementAndGet();
}
@Override
public List<HBData> collectData()
{
List<HBData> collectedData = new LinkedList<>();
String systemId = this.currentRepoDescriptorDAO.getDescriptor().getId();
String collectorId = this.getCollectorId();
String collectorVersion = this.getCollectorVersion();
Date timestamp = new Date();
// We don't mind if new renditions are added while we iterate, as we will pick them up next time.
for (ThumbnailDefinition rendition : renditionRequests.keySet())
{
String renditionName = rendition.getName();
String targetMimetype = rendition.getMimetype();
for (Map.Entry<String, AtomicInteger> entry: renditionRequests.remove(rendition).entrySet())
{
String sourceMimetype = entry.getKey();
AtomicInteger count = entry.getValue();
Map<String, Object> values = new HashMap<>();
values.put("rendition", renditionName);
values.put("count", count.intValue());
values.put("sourceMimetype", sourceMimetype);
values.put("targetMimetype", targetMimetype);
// Decided it would be simpler to be able to combine results in Kibana from different nodes
// and days if the data was flattened (denormalized) out at this point. It is very likely
// that different nodes would have different sets of sourceMimetypes which would make summing
// the counts harder to do, if there was a single entry for each rendition with a nested
// structure for each sourceMimetype.
collectedData.add(new HBData(systemId, collectorId, collectorVersion, timestamp, values));
if (logger.isDebugEnabled())
{
logger.debug(renditionName+" "+count+" "+sourceMimetype+" "+targetMimetype);
}
}
}
return collectedData;
}
}

View File

@@ -0,0 +1,196 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.opencmis;
import javax.servlet.http.HttpServletRequest;
import org.alfresco.opencmis.CMISDispatcherRegistry.Binding;
import org.alfresco.repo.tenant.TenantUtil;
/**
* Generates an OpenCMIS base url based on the request, repository id and binding.
*
* @author steveglover
*
*/
public abstract class AbstractBaseUrlGenerator implements BaseUrlGenerator
{
private boolean overrideContext;
private String contextOverride;
private boolean overrideServletPath;
private String servletPathOverride;
private PathGenerator pathGenerator;
public void setPathGenerator(PathGenerator pathGenerator)
{
this.pathGenerator = pathGenerator;
}
public void setOverrideContext(boolean overrideContext)
{
this.overrideContext = overrideContext;
}
private String fixup(String urlSegment)
{
StringBuilder sb = new StringBuilder();
int beginIndex = 0;
int endIndex = urlSegment.length();
if(urlSegment != null)
{
if(!urlSegment.equals("") && !urlSegment.startsWith("/"))
{
sb.append("/");
}
if(urlSegment.endsWith("/"))
{
endIndex -= 1;
}
}
sb.append(urlSegment.substring(beginIndex, endIndex));
return sb.toString();
}
public void setContextOverride(String contextOverride)
{
this.contextOverride = fixup(contextOverride);
}
public void setOverrideServletPath(boolean overrideServletPath)
{
this.overrideServletPath = overrideServletPath;
}
public void setServletPathOverride(String servletPathOverride)
{
this.servletPathOverride = fixup(servletPathOverride);
}
protected abstract String getServerPath(HttpServletRequest request);
public String getContextPath(HttpServletRequest httpReq)
{
if(overrideContext)
{
return contextOverride;
}
else
{
return httpReq.getContextPath();
}
}
public String getServletPath(HttpServletRequest req)
{
if(overrideServletPath)
{
return servletPathOverride;
}
else
{
return req.getServletPath();
}
}
@Override
public String getRequestURI(HttpServletRequest req, String repositoryId, String operation, String id)
{
StringBuilder url = new StringBuilder();
String contextPath = getContextPath(req);
if(contextPath != null && !contextPath.equals(""))
{
url.append(contextPath);
}
String servletPath = getServletPath(req);
if(servletPath != null && !servletPath.equals(""))
{
url.append(servletPath);
url.append("/");
}
if(url.length() == 0 || url.charAt(0) != '/')
{
url.append("/");
}
if(repositoryId != null)
{
url.append(repositoryId == null ? TenantUtil.DEFAULT_TENANT : repositoryId);
url.append("/");
}
if(operation != null)
{
url.append(operation);
url.append("/");
}
if(id != null)
{
url.append(id);
}
int length = url.length();
if(length > 0 && url.charAt(length - 1) == '/')
{
url.deleteCharAt(length - 1);
}
return url.toString();
}
@Override
public String getBaseUrl(HttpServletRequest req, String repositoryId, Binding binding)
{
StringBuilder url = new StringBuilder();
String serverPath = getServerPath(req);
url.append(serverPath);
String contextPath = getContextPath(req);
if(contextPath != null && !contextPath.equals(""))
{
url.append(contextPath);
}
String servletPath = getServletPath(req);
if(servletPath != null && !servletPath.equals(""))
{
url.append(servletPath);
url.append("/");
}
if(url.length() > 0 && url.charAt(url.length() - 1) != '/')
{
url.append("/");
}
pathGenerator.generatePath(req, url, repositoryId, binding);
return url.toString();
}
}

View File

@@ -0,0 +1,52 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.opencmis;
import javax.servlet.http.HttpServlet;
import org.alfresco.opencmis.CMISDispatcherRegistry.Binding;
import org.apache.chemistry.opencmis.server.impl.atompub.CmisAtomPubServlet;
/**
* Dispatches OpenCMIS requests to the OpenCMIS AtomPub servlet.
*
* @author steveglover
*
*/
public class AtomPubCMISDispatcher extends CMISServletDispatcher
{
@Override
protected Binding getBinding()
{
return Binding.atom;
}
protected HttpServlet getServlet()
{
HttpServlet servlet = new CmisAtomPubServlet();
return servlet;
}
}

View File

@@ -0,0 +1,44 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.opencmis;
import javax.servlet.http.HttpServletRequest;
import org.alfresco.opencmis.CMISDispatcherRegistry.Binding;
/**
* Generates an OpenCMIS base url based on the request, repository id and binding.
*
* @author steveglover
*
*/
public interface BaseUrlGenerator
{
String getContextPath(HttpServletRequest httpReq);
String getServletPath(HttpServletRequest req);
String getBaseUrl(HttpServletRequest req, String repositoryId, Binding binding);
String getRequestURI(HttpServletRequest req, String repositoryId, String operation, String id);
}

View File

@@ -0,0 +1,52 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.opencmis;
import javax.servlet.http.HttpServlet;
import org.alfresco.opencmis.CMISDispatcherRegistry.Binding;
import org.apache.chemistry.opencmis.server.impl.browser.CmisBrowserBindingServlet;
/**
* Dispatches OpenCMIS requests to the OpenCMIS Browser Binding servlet.
*
* @author steveglover
*
*/
public class BrowserCMISDispatcher extends CMISServletDispatcher
{
@Override
protected Binding getBinding()
{
return Binding.browser;
}
protected HttpServlet getServlet()
{
HttpServlet servlet = new CmisBrowserBindingServlet();
return servlet;
}
}

View File

@@ -0,0 +1,42 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.opencmis;
import java.io.IOException;
import org.springframework.extensions.webscripts.WebScriptRequest;
import org.springframework.extensions.webscripts.WebScriptResponse;
/**
* Dispatches OpenCMIS requests to the appropriate handler.
*
* @author steveglover
*
*/
public interface CMISDispatcher
{
public void execute(WebScriptRequest req, WebScriptResponse res) throws IOException;
}

View File

@@ -0,0 +1,120 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.opencmis;
import org.apache.chemistry.opencmis.commons.enums.BindingType;
import org.springframework.extensions.webscripts.WebScriptRequest;
/**
* A registry of OpenCMIS bindings to dispatchers.
*
* @author steveglover
*
*/
public interface CMISDispatcherRegistry
{
/*
* Supported CMIS bindings
*/
public static enum Binding
{
atom, browser;
public BindingType getOpenCmisBinding()
{
BindingType bindingType = null;
if(this == atom)
{
bindingType = BindingType.ATOMPUB;
}
else if(this == browser)
{
bindingType = BindingType.BROWSER;
}
return bindingType;
}
};
public static class Endpoint
{
private Binding binding;
private String version;
public Endpoint(Binding binding, String version)
{
super();
this.binding = binding;
this.version = version;
}
public Binding getBinding()
{
return binding;
}
public String getVersion()
{
return version;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result
+ ((binding == null) ? 0 : binding.hashCode());
result = prime * result
+ ((version == null) ? 0 : version.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Endpoint other = (Endpoint) obj;
if (binding != other.binding)
return false;
if (version == null) {
if (other.version != null)
return false;
} else if (!version.equals(other.version))
return false;
return true;
}
}
public void registerDispatcher(Endpoint endpoint, CMISDispatcher dispatcher);
public CMISDispatcher getDispatcher(WebScriptRequest req);
}

View File

@@ -0,0 +1,84 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.opencmis;
import java.util.HashMap;
import java.util.Map;
import org.springframework.extensions.webscripts.Match;
import org.springframework.extensions.webscripts.WebScriptRequest;
/**
* A registry of OpenCMIS bindings to dispatchers.
*
* @author steveglover
*
*/
public class CMISDispatcherRegistryImpl implements CMISDispatcherRegistry
{
private Map<Endpoint, CMISDispatcher> registry = new HashMap<Endpoint, CMISDispatcher>();
@Override
public void registerDispatcher(Endpoint endpoint, CMISDispatcher dispatcher)
{
registry.put(endpoint, dispatcher);
}
@Override
public CMISDispatcher getDispatcher(WebScriptRequest req)
{
CMISDispatcher dispatcher = null;
Match match = req.getServiceMatch();
Map<String, String> templateVars = match.getTemplateVars();
String bindingStr = templateVars.get("binding");
String apiVersion = templateVars.get("apiVersion");
if(bindingStr != null && apiVersion != null)
{
Binding binding = null;
try
{
binding = Binding.valueOf(bindingStr);
}
catch(IllegalArgumentException e)
{
// nothing to do, binding remains null
}
if(binding != null)
{
Endpoint endpoint = new Endpoint(binding, apiVersion);
dispatcher = registry.get(endpoint);
}
else
{
// TODO
}
}
return dispatcher;
}
}

View File

@@ -0,0 +1,643 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.opencmis;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.servlet.AsyncContext;
import javax.servlet.DispatcherType;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.http.Part;
import org.alfresco.opencmis.CMISDispatcherRegistry.Binding;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.tenant.TenantAdminService;
import org.alfresco.repo.tenant.TenantService;
import org.alfresco.repo.tenant.TenantUtil;
import org.alfresco.repo.web.scripts.TenantWebScriptServletRequest;
import org.alfresco.service.descriptor.Descriptor;
import org.apache.chemistry.opencmis.commons.impl.Constants;
import org.apache.chemistry.opencmis.server.shared.Dispatcher;
import org.apache.commons.collections.map.HashedMap;
import org.springframework.extensions.webscripts.Match;
import org.springframework.extensions.webscripts.WebScriptRequest;
import org.springframework.extensions.webscripts.WrappingWebScriptRequest;
import org.springframework.extensions.webscripts.servlet.WebScriptServletRuntime;
/**
* Wraps an OpenCMIS HttpServletRequest, mapping urls and adding servlet attributes specific to the Alfresco implementation of OpenCMIS.
*/
@SuppressWarnings("rawtypes")
public class CMISHttpServletRequest implements HttpServletRequest
{
protected WebScriptRequest req;
protected HttpServletRequest httpReq;
protected String networkId;
protected String operation;
protected String id; // object id (or path for browser binding)
protected String serviceName;
protected BaseUrlGenerator baseUrlGenerator;
protected Binding binding;
protected Descriptor currentDescriptor;
public CMISHttpServletRequest(WebScriptRequest req, String serviceName, BaseUrlGenerator baseUrlGenerator, Binding binding, Descriptor currentDescriptor,
TenantAdminService tenantAdminService)
{
this.req = req;
this.serviceName = serviceName;
this.baseUrlGenerator = baseUrlGenerator;
this.binding = binding;
String pathInfo = req.getPathInfo();
WebScriptRequest baseReq = getBaseRequest(req);
if(!pathInfo.startsWith("/cmis") && (baseReq instanceof TenantWebScriptServletRequest))
{
TenantWebScriptServletRequest servletReq = (TenantWebScriptServletRequest)baseReq;
String tenant = servletReq.getTenant();
if(tenant.equalsIgnoreCase(TenantUtil.DEFAULT_TENANT))
{
String user = AuthenticationUtil.getFullyAuthenticatedUser();
String domain = tenantAdminService.getUserDomain(user);
if(domain == null || domain.equals(TenantService.DEFAULT_DOMAIN))
{
this.networkId = tenant;
}
else
{
this.networkId = domain;
}
}
else
{
this.networkId = tenant;
}
}
Match match = req.getServiceMatch();
Map<String, String> templateVars = match.getTemplateVars();
HttpServletRequest httpReq = WebScriptServletRuntime.getHttpServletRequest(req);
this.httpReq = httpReq;
this.operation = templateVars.get("operation");
this.id = templateVars.get("id");
addAttributes();
}
/*
* Recursively unwrap req if it is a WrappingWebScriptRequest
*/
private WebScriptRequest getBaseRequest(WebScriptRequest req)
{
WebScriptRequest ret = req;
while(ret instanceof WrappingWebScriptRequest)
{
WrappingWebScriptRequest wrapping = (WrappingWebScriptRequest)req;
ret = wrapping.getNext();
}
return ret;
}
protected void addAttributes()
{
if(networkId != null)
{
httpReq.setAttribute(Constants.PARAM_REPOSITORY_ID, networkId);
}
httpReq.setAttribute("serviceName", serviceName);
}
@Override
public Object getAttribute(String arg0)
{
if(arg0.equals(Dispatcher.BASE_URL_ATTRIBUTE))
{
return baseUrlGenerator.getBaseUrl(this, networkId, binding);
}
else
{
return httpReq.getAttribute(arg0);
}
}
@SuppressWarnings("unchecked")
@Override
public Enumeration getAttributeNames()
{
Enumeration e = httpReq.getAttributeNames();
List attrNames = new ArrayList();
while(e.hasMoreElements())
{
attrNames.add(e.nextElement());
}
attrNames.add(Dispatcher.BASE_URL_ATTRIBUTE);
final Iterator it = attrNames.iterator();
return new Enumeration()
{
public boolean hasMoreElements()
{
return it.hasNext();
}
public Object nextElement()
{
return it.next();
}
};
}
@Override
public String getCharacterEncoding()
{
return httpReq.getCharacterEncoding();
}
@Override
public int getContentLength()
{
return httpReq.getContentLength();
}
@Override
public String getContentType()
{
return httpReq.getContentType();
}
@Override
public ServletInputStream getInputStream() throws IOException
{
return httpReq.getInputStream();
}
@Override
public String getLocalAddr()
{
return httpReq.getLocalAddr();
}
@Override
public String getLocalName()
{
return httpReq.getLocalName();
}
@Override
public int getLocalPort()
{
return httpReq.getLocalPort();
}
@Override
public Locale getLocale()
{
return httpReq.getLocale();
}
@Override
public Enumeration getLocales()
{
return httpReq.getLocales();
}
@Override
public String getParameter(String arg0)
{
if(arg0.equals(Constants.PARAM_REPOSITORY_ID))
{
return networkId;
}
return httpReq.getParameter(arg0);
}
@SuppressWarnings("unchecked")
@Override
public Map getParameterMap()
{
Map map = httpReq.getParameterMap();
Map ret = new HashedMap(map);
if(networkId != null)
{
ret.put(Constants.PARAM_REPOSITORY_ID, new String[] { networkId });
}
return ret;
}
@SuppressWarnings("unchecked")
@Override
public Enumeration getParameterNames()
{
final Enumeration e = httpReq.getParameterNames();
List l = new ArrayList();
while(e.hasMoreElements())
{
l.add(e.nextElement());
}
if(networkId != null)
{
l.add(Constants.PARAM_REPOSITORY_ID);
}
final Iterator it = l.iterator();
Enumeration ret = new Enumeration()
{
@Override
public boolean hasMoreElements()
{
return it.hasNext();
}
@Override
public Object nextElement()
{
return it.next();
}
};
return ret;
}
@Override
public String[] getParameterValues(String arg0)
{
return httpReq.getParameterValues(arg0);
}
@Override
public String getProtocol()
{
return httpReq.getProtocol();
}
@Override
public BufferedReader getReader() throws IOException
{
return httpReq.getReader();
}
@SuppressWarnings("deprecation")
@Override
public String getRealPath(String arg0)
{
return httpReq.getRealPath(arg0);
}
@Override
public String getRemoteAddr()
{
return httpReq.getRemoteAddr();
}
@Override
public String getRemoteHost()
{
return httpReq.getRemoteHost();
}
@Override
public int getRemotePort()
{
return httpReq.getRemotePort();
}
@Override
public RequestDispatcher getRequestDispatcher(String arg0)
{
return httpReq.getRequestDispatcher(arg0);
}
@Override
public String getScheme()
{
return httpReq.getScheme();
}
@Override
public String getServerName()
{
return httpReq.getServerName();
}
@Override
public int getServerPort()
{
return httpReq.getServerPort();
}
@Override
public boolean isSecure()
{
return httpReq.isSecure();
}
@Override
public void removeAttribute(String arg0)
{
httpReq.removeAttribute(arg0);
}
@Override
public void setAttribute(String arg0, Object arg1)
{
httpReq.setAttribute(arg0, arg1);
}
@Override
public void setCharacterEncoding(String arg0) throws UnsupportedEncodingException
{
httpReq.setCharacterEncoding(arg0);
}
@Override
public String getAuthType()
{
return httpReq.getAuthType();
}
@Override
public String getContextPath()
{
String contextPath = baseUrlGenerator.getContextPath(httpReq);
return contextPath;
}
@Override
public Cookie[] getCookies()
{
return httpReq.getCookies();
}
@Override
public long getDateHeader(String arg0)
{
return httpReq.getDateHeader(arg0);
}
@Override
public String getHeader(String arg0)
{
return httpReq.getHeader(arg0);
}
@Override
public Enumeration getHeaderNames()
{
return httpReq.getHeaderNames();
}
@Override
public Enumeration getHeaders(String arg0)
{
return httpReq.getHeaders(arg0);
}
@Override
public int getIntHeader(String arg0)
{
return httpReq.getIntHeader(arg0);
}
@Override
public String getMethod()
{
return httpReq.getMethod();
}
@Override
public String getPathInfo()
{
StringBuilder sb = new StringBuilder("/");
sb.append(networkId == null ? TenantUtil.DEFAULT_TENANT : networkId);
if(operation != null)
{
sb.append("/");
sb.append(operation);
}
return sb.toString();
}
@Override
public String getPathTranslated()
{
return httpReq.getPathTranslated();
}
@Override
public String getQueryString()
{
StringBuilder queryString = new StringBuilder();
String reqQueryString = httpReq.getQueryString();
if(networkId != null && networkId.length() > 0)
{
if (reqQueryString != null)
{
queryString.append(reqQueryString + "&");
}
queryString.append("repositoryId=" + networkId);
if(operation == null || operation.isEmpty())
{
queryString.append("&cmisselector=");
queryString.append(Constants.SELECTOR_REPOSITORY_INFO);
}
return queryString.toString();
}
return reqQueryString;
}
@Override
public String getRemoteUser()
{
return httpReq.getRemoteUser();
}
@Override
public String getRequestURI()
{
String requestURI = baseUrlGenerator.getRequestURI(httpReq, networkId, operation, id);
return requestURI;
}
@Override
public StringBuffer getRequestURL()
{
return httpReq.getRequestURL();
}
@Override
public String getRequestedSessionId()
{
return httpReq.getRequestedSessionId();
}
@Override
public String getServletPath()
{
String servletPath = baseUrlGenerator.getServletPath(httpReq);
return servletPath;
}
@Override
public HttpSession getSession()
{
return httpReq.getSession();
}
@Override
public HttpSession getSession(boolean arg0)
{
return httpReq.getSession(arg0);
}
@Override
public Principal getUserPrincipal()
{
return httpReq.getUserPrincipal();
}
@Override
public boolean isRequestedSessionIdFromCookie()
{
return httpReq.isRequestedSessionIdFromCookie();
}
@Override
public boolean isRequestedSessionIdFromURL()
{
return httpReq.isRequestedSessionIdFromURL();
}
@Override
public boolean isRequestedSessionIdFromUrl()
{
return httpReq.isRequestedSessionIdFromURL();
}
@Override
public boolean isRequestedSessionIdValid()
{
return httpReq.isRequestedSessionIdValid();
}
@Override
public boolean isUserInRole(String arg0)
{
return httpReq.isUserInRole(arg0);
}
@Override
public boolean authenticate(HttpServletResponse response) throws IOException, ServletException
{
return httpReq.authenticate(response);
}
@Override
public void login(String username, String password) throws ServletException
{
httpReq.login(username, password);
}
@Override
public void logout() throws ServletException
{
httpReq.logout();
}
@Override
public Collection<Part> getParts() throws IOException, ServletException
{
return httpReq.getParts();
}
@Override
public Part getPart(String name) throws IOException, ServletException
{
return httpReq.getPart(name);
}
@Override
public ServletContext getServletContext()
{
return httpReq.getServletContext();
}
@Override
public AsyncContext startAsync() throws IllegalStateException
{
return httpReq.startAsync();
}
@Override
public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException
{
return httpReq.startAsync(servletRequest, servletResponse);
}
@Override
public boolean isAsyncStarted()
{
return httpReq.isAsyncStarted();
}
@Override
public boolean isAsyncSupported()
{
return httpReq.isAsyncSupported();
}
@Override
public AsyncContext getAsyncContext()
{
return httpReq.getAsyncContext();
}
@Override
public DispatcherType getDispatcherType()
{
return httpReq.getDispatcherType();
}
}

View File

@@ -0,0 +1,302 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.opencmis;
import org.alfresco.error.AlfrescoRuntimeException;
import org.springframework.extensions.webscripts.WebScriptResponse;
import org.springframework.extensions.webscripts.servlet.WebScriptServletRuntime;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.Collections;
import java.util.Locale;
import java.util.Set;
/**
* Wraps an OpenCMIS HttpServletResponse for specific mapping to the Alfresco implementation of OpenCMIS.
*
* @author janv
*/
public class CMISHttpServletResponse implements HttpServletResponse
{
protected HttpServletResponse httpResp;
protected Set<String> nonAttachContentTypes = Collections.emptySet(); // pre-configured whitelist, eg. images & pdf
private final static String HDR_CONTENT_DISPOSITION = "Content-Disposition";
private final static String ATTACHMENT = "attachment";
private final static String INLINE = "inline";
public CMISHttpServletResponse(WebScriptResponse res, Set<String> nonAttachContentTypes)
{
httpResp = WebScriptServletRuntime.getHttpServletResponse(res);
this.nonAttachContentTypes = nonAttachContentTypes;
}
@Override
public void addCookie(Cookie cookie)
{
httpResp.addCookie(cookie);
}
@Override
public boolean containsHeader(String name)
{
return httpResp.containsHeader(name);
}
@Override
public String encodeURL(String url)
{
return httpResp.encodeURL(url);
}
@Override
public String encodeRedirectURL(String url)
{
return httpResp.encodeRedirectURL(url);
}
@Override
public String encodeUrl(String url)
{
return encodeUrl(url);
}
@Override
public String encodeRedirectUrl(String url)
{
return httpResp.encodeRedirectUrl(url);
}
@Override
public void sendError(int sc, String msg) throws IOException
{
httpResp.sendError(sc, msg);
}
@Override
public void sendError(int sc) throws IOException
{
httpResp.sendError(sc);
}
@Override
public void sendRedirect(String location) throws IOException
{
httpResp.sendRedirect(location);
}
@Override
public void setDateHeader(String name, long date)
{
httpResp.setDateHeader(name, date);
}
@Override
public void addDateHeader(String name, long date)
{
httpResp.addDateHeader(name, date);
}
@Override
public void setHeader(String name, String value)
{
httpResp.setHeader(name, getStringHeaderValue(name, value, httpResp.getContentType()));
}
@Override
public void addHeader(String name, String value)
{
httpResp.addHeader(name, getStringHeaderValue(name, value, httpResp.getContentType()));
}
private String getStringHeaderValue(String name, String value, String contentType)
{
if (HDR_CONTENT_DISPOSITION.equals(name))
{
if (! nonAttachContentTypes.contains(contentType))
{
if (value.startsWith(INLINE))
{
// force attachment
value = ATTACHMENT+value.substring(INLINE.length());
}
else if (! value.startsWith(ATTACHMENT))
{
throw new AlfrescoRuntimeException("Unexpected - header could not be set: "+name+" = "+value);
}
}
}
return value;
}
@Override
public void setIntHeader(String name, int value)
{
httpResp.setIntHeader(name, value);
}
@Override
public void addIntHeader(String name, int value)
{
httpResp.addIntHeader(name, value);
}
@Override
public void setStatus(int sc)
{
httpResp.setStatus(sc);
}
@Override
public void setStatus(int sc, String sm)
{
httpResp.setStatus(sc, sm);
}
@Override
public int getStatus()
{
return httpResp.getStatus();
}
@Override
public String getHeader(String name)
{
return httpResp.getHeader(name);
}
@Override
public Collection<String> getHeaders(String name)
{
return httpResp.getHeaders(name);
}
@Override
public Collection<String> getHeaderNames()
{
return httpResp.getHeaderNames();
}
@Override
public String getCharacterEncoding()
{
return httpResp.getCharacterEncoding();
}
@Override
public String getContentType()
{
return httpResp.getContentType();
}
@Override
public ServletOutputStream getOutputStream() throws IOException
{
return httpResp.getOutputStream();
}
@Override
public PrintWriter getWriter() throws IOException
{
return httpResp.getWriter();
}
@Override
public void setCharacterEncoding(String charset)
{
httpResp.setCharacterEncoding(charset);
}
@Override
public void setContentLength(int len)
{
httpResp.setContentLength(len);
}
@Override
public void setContentType(String type)
{
httpResp.setContentType(type);
}
@Override
public void setBufferSize(int size)
{
httpResp.setBufferSize(size);
}
@Override
public int getBufferSize()
{
return httpResp.getBufferSize();
}
@Override
public void flushBuffer() throws IOException
{
httpResp.flushBuffer();
}
@Override
public void resetBuffer()
{
httpResp.resetBuffer();
}
@Override
public boolean isCommitted()
{
return httpResp.isCommitted();
}
@Override
public void reset()
{
httpResp.reset();
}
@Override
public void setLocale(Locale loc)
{
httpResp.setLocale(loc);
}
@Override
public Locale getLocale()
{
return httpResp.getLocale();
}
}

View File

@@ -0,0 +1,601 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.opencmis;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.EventListener;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import javax.servlet.Filter;
import javax.servlet.FilterRegistration;
import javax.servlet.RequestDispatcher;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRegistration;
import javax.servlet.SessionCookieConfig;
import javax.servlet.SessionTrackingMode;
import javax.servlet.descriptor.JspConfigDescriptor;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.opencmis.CMISDispatcherRegistry.Binding;
import org.alfresco.opencmis.CMISDispatcherRegistry.Endpoint;
import org.alfresco.repo.tenant.TenantAdminService;
import org.alfresco.service.descriptor.Descriptor;
import org.alfresco.service.descriptor.DescriptorService;
import org.apache.chemistry.opencmis.commons.enums.CmisVersion;
import org.apache.chemistry.opencmis.commons.server.CmisServiceFactory;
import org.apache.chemistry.opencmis.server.impl.CmisRepositoryContextListener;
import org.apache.chemistry.opencmis.server.impl.atompub.CmisAtomPubServlet;
import org.springframework.extensions.webscripts.WebScriptRequest;
import org.springframework.extensions.webscripts.WebScriptResponse;
import org.springframework.extensions.webscripts.servlet.WebScriptServletRuntime;
/**
* Dispatches OpenCMIS requests to a servlet e.g. the OpenCMIS AtomPub servlet.
*
* @author steveglover
*
*/
public abstract class CMISServletDispatcher implements CMISDispatcher
{
private DescriptorService descriptorService;
private Descriptor currentDescriptor;
protected CmisServiceFactory cmisServiceFactory;
protected HttpServlet servlet;
protected CMISDispatcherRegistry registry;
protected String serviceName;
protected BaseUrlGenerator baseUrlGenerator;
protected String version;
protected CmisVersion cmisVersion;
protected TenantAdminService tenantAdminService;
private Set<String> nonAttachContentTypes = Collections.emptySet(); // pre-configured whitelist, eg. images & pdf
public void setTenantAdminService(TenantAdminService tenantAdminService)
{
this.tenantAdminService = tenantAdminService;
}
public void setDescriptorService(DescriptorService descriptorService)
{
this.descriptorService = descriptorService;
}
public void setVersion(String version)
{
this.version = version;
}
public void setBaseUrlGenerator(BaseUrlGenerator baseUrlGenerator)
{
this.baseUrlGenerator = baseUrlGenerator;
}
public void setRegistry(CMISDispatcherRegistry registry)
{
this.registry = registry;
}
public void setCmisServiceFactory(CmisServiceFactory cmisServiceFactory)
{
this.cmisServiceFactory = cmisServiceFactory;
}
public void setServiceName(String serviceName)
{
this.serviceName = serviceName;
}
public String getServiceName()
{
return serviceName;
}
public void setCmisVersion(String cmisVersion)
{
this.cmisVersion = CmisVersion.fromValue(cmisVersion);
}
public void setNonAttachContentTypes(Set<String> nonAttachWhiteList)
{
this.nonAttachContentTypes = nonAttachWhiteList;
}
protected synchronized Descriptor getCurrentDescriptor()
{
if(this.currentDescriptor == null)
{
this.currentDescriptor = descriptorService.getCurrentRepositoryDescriptor();
}
return this.currentDescriptor;
}
public void init()
{
Endpoint endpoint = new Endpoint(getBinding(), version);
registry.registerDispatcher(endpoint, this);
try
{
// fake the CMIS servlet
ServletConfig config = getServletConfig();
this.servlet = getServlet();
servlet.init(config);
}
catch(ServletException e)
{
throw new AlfrescoRuntimeException("Failed to initialise CMIS servlet dispatcher", e);
}
}
/*
* Implement getBinding to provide the appropriate CMIS binding.
*/
protected abstract Binding getBinding();
/*
* Implement getServlet to provide the appropriate servlet implementation.
*/
protected abstract HttpServlet getServlet();
protected Object getServletAttribute(String attrName)
{
if(attrName.equals(CmisRepositoryContextListener.SERVICES_FACTORY))
{
return cmisServiceFactory;
}
return null;
}
protected ServletConfig getServletConfig()
{
ServletConfig config = new CMISServletConfig();
return config;
}
protected CMISHttpServletRequest getHttpRequest(WebScriptRequest req)
{
String serviceName = getServiceName();
CMISHttpServletRequest httpReqWrapper = new CMISHttpServletRequest(req, serviceName, baseUrlGenerator,
getBinding(), currentDescriptor, tenantAdminService);
return httpReqWrapper;
}
protected CMISHttpServletResponse getHttpResponse(WebScriptResponse res)
{
CMISHttpServletResponse httpResWrapper = new CMISHttpServletResponse(res, nonAttachContentTypes);
return httpResWrapper;
}
public void execute(WebScriptRequest req, WebScriptResponse res) throws IOException
{
try
{
// wrap request & response
CMISHttpServletResponse httpResWrapper = getHttpResponse(res);
CMISHttpServletRequest httpReqWrapper = getHttpRequest(req);
servlet.service(httpReqWrapper, httpResWrapper);
}
catch(ServletException e)
{
throw new AlfrescoRuntimeException("", e);
}
}
/**
* Fake a CMIS servlet config.
*
* @author steveglover
*
*/
@SuppressWarnings("rawtypes")
private class CMISServletConfig implements ServletConfig
{
private List parameterNames = new ArrayList();
@SuppressWarnings("unchecked")
CMISServletConfig()
{
parameterNames.add(CmisAtomPubServlet.PARAM_CALL_CONTEXT_HANDLER);
parameterNames.add(CmisAtomPubServlet.PARAM_CMIS_VERSION);
}
@Override
public String getInitParameter(String arg0)
{
if(arg0.equals(CmisAtomPubServlet.PARAM_CALL_CONTEXT_HANDLER))
{
return PublicApiCallContextHandler.class.getName();
}
else if(arg0.equals(CmisAtomPubServlet.PARAM_CMIS_VERSION))
{
return (cmisVersion != null ? cmisVersion.value() : CmisVersion.CMIS_1_0.value());
}
return null;
}
@Override
public Enumeration getInitParameterNames()
{
final Iterator it = parameterNames.iterator();
Enumeration e = new Enumeration()
{
@Override
public boolean hasMoreElements()
{
return it.hasNext();
}
@Override
public Object nextElement()
{
return it.next();
}
};
return e;
}
// fake a servlet context. Note that getAttribute is the only method that the servlet uses,
// hence the other methods are not implemented.
@Override
public ServletContext getServletContext()
{
return new ServletContext()
{
@Override
public Object getAttribute(String arg0)
{
return getServletAttribute(arg0);
}
@Override
public Enumeration getAttributeNames()
{
return null;
}
@Override
public String getContextPath()
{
return null;
}
@Override
public ServletContext getContext(String arg0)
{
return null;
}
@Override
public String getInitParameter(String arg0)
{
return null;
}
@Override
public Enumeration getInitParameterNames()
{
return null;
}
@Override
public boolean setInitParameter(String name, String value)
{
return false;
}
@Override
public int getMajorVersion()
{
return 0;
}
@Override
public String getMimeType(String arg0)
{
return null;
}
@Override
public int getMinorVersion()
{
return 0;
}
@Override
public int getEffectiveMajorVersion()
{
return 0;
}
@Override
public int getEffectiveMinorVersion()
{
return 0;
}
@Override
public RequestDispatcher getNamedDispatcher(String arg0)
{
return null;
}
@Override
public String getRealPath(String arg0)
{
return null;
}
@Override
public RequestDispatcher getRequestDispatcher(String arg0)
{
return null;
}
@Override
public URL getResource(String arg0) throws MalformedURLException
{
return null;
}
@Override
public InputStream getResourceAsStream(String arg0)
{
return null;
}
@Override
public Set getResourcePaths(String arg0)
{
return null;
}
@Override
public String getServerInfo()
{
return null;
}
@Override
public Servlet getServlet(String arg0) throws ServletException
{
return null;
}
@Override
public String getServletContextName()
{
return null;
}
@Override
public ServletRegistration.Dynamic addServlet(String servletName, String className)
{
return null;
}
@Override
public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet)
{
return null;
}
@Override
public ServletRegistration.Dynamic addServlet(String servletName, Class<? extends Servlet> servletClass)
{
return null;
}
@Override
public <T extends Servlet> T createServlet(Class<T> clazz) throws ServletException
{
return null;
}
@Override
public ServletRegistration getServletRegistration(String servletName)
{
return null;
}
@Override
public Map<String, ? extends ServletRegistration> getServletRegistrations()
{
return null;
}
@Override
public FilterRegistration.Dynamic addFilter(String filterName, String className)
{
return null;
}
@Override
public FilterRegistration.Dynamic addFilter(String filterName, Filter filter)
{
return null;
}
@Override
public FilterRegistration.Dynamic addFilter(String filterName, Class<? extends Filter> filterClass)
{
return null;
}
@Override
public <T extends Filter> T createFilter(Class<T> clazz) throws ServletException
{
return null;
}
@Override
public FilterRegistration getFilterRegistration(String filterName)
{
return null;
}
@Override
public Map<String, ? extends FilterRegistration> getFilterRegistrations()
{
return null;
}
@Override
public SessionCookieConfig getSessionCookieConfig()
{
return null;
}
@Override
public void setSessionTrackingModes(Set<SessionTrackingMode> sessionTrackingModes)
{
}
@Override
public Set<SessionTrackingMode> getDefaultSessionTrackingModes()
{
return null;
}
@Override
public Set<SessionTrackingMode> getEffectiveSessionTrackingModes()
{
return null;
}
@Override
public void addListener(String className)
{
}
@Override
public <T extends EventListener> void addListener(T t)
{
}
@Override
public void addListener(Class<? extends EventListener> listenerClass)
{
}
@Override
public <T extends EventListener> T createListener(Class<T> clazz) throws ServletException
{
return null;
}
@Override
public JspConfigDescriptor getJspConfigDescriptor()
{
return null;
}
@Override
public ClassLoader getClassLoader()
{
return null;
}
@Override
public void declareRoles(String... roleNames)
{
}
@Override
public Enumeration getServletNames()
{
return null;
}
@Override
public Enumeration getServlets()
{
return null;
}
@Override
public void log(String arg0)
{
}
@Override
public void log(Exception arg0, String arg1)
{
}
@Override
public void log(String arg0, Throwable arg1)
{
}
@Override
public void removeAttribute(String arg0)
{
}
@Override
public void setAttribute(String arg0, Object arg1)
{
}
};
}
@Override
public String getServletName()
{
return "OpenCMIS";
}
}
}

View File

@@ -0,0 +1,61 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.opencmis;
import java.io.IOException;
import org.springframework.extensions.webscripts.AbstractWebScript;
import org.springframework.extensions.webscripts.WebScriptRequest;
import org.springframework.extensions.webscripts.WebScriptResponse;
/**
* An Alfresco web script that handles dispatch of OpenCMIS requests.
*
* @author steveglover
*
*/
public class CMISWebScript extends AbstractWebScript
{
private CMISDispatcherRegistry registry;
public void setRegistry(CMISDispatcherRegistry registry)
{
this.registry = registry;
}
public void execute(WebScriptRequest req, WebScriptResponse res) throws IOException
{
CMISDispatcher dispatcher = registry.getDispatcher(req);
if(dispatcher == null)
{
res.setStatus(404);
}
else
{
dispatcher.execute(req, res);
}
}
}

View File

@@ -0,0 +1,74 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.opencmis;
import javax.servlet.http.HttpServletRequest;
/**
* Generates an OpenCMIS base url based on the request, repository id and binding. The url scheme, host and port
* are overridden by a property from repository.properties or in an override file.
*
* @author steveglover
*
*/
public class DefaultBaseUrlGenerator extends AbstractBaseUrlGenerator
{
private boolean overrideServer;
private String serverOverride;
public DefaultBaseUrlGenerator()
{
}
public void setOverrideServer(boolean overrideServer)
{
this.overrideServer = overrideServer;
}
public void setServerOverride(String serverOverride)
{
this.serverOverride = serverOverride;
}
protected String getServerPath(HttpServletRequest request)
{
if(overrideServer)
{
return serverOverride;
}
else
{
StringBuilder sb = new StringBuilder();
sb.append(request.getScheme());
sb.append("://");
sb.append(request.getServerName());
sb.append(":");
sb.append(request.getServerPort());
return sb.toString();
}
}
}

View File

@@ -0,0 +1,55 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.opencmis;
import javax.servlet.http.HttpServletRequest;
import org.alfresco.opencmis.CMISDispatcherRegistry.Binding;
import org.alfresco.repo.tenant.TenantUtil;
/**
* Default generator for OpenCMIS paths based on the repositoryId and binding.
*
* @author steveglover
*
*/
public class DefaultPathGenerator implements PathGenerator
{
public void generatePath(HttpServletRequest req, StringBuilder url, String repositoryId, Binding binding)
{
url.append(binding.toString());
url.append("/");
if(repositoryId != null)
{
url.append(repositoryId);
}
else
{
url.append(TenantUtil.DEFAULT_TENANT);
}
}
}

View File

@@ -0,0 +1,41 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.opencmis;
import javax.servlet.http.HttpServletRequest;
import org.alfresco.opencmis.CMISDispatcherRegistry.Binding;
/**
* Generates an OpenCMIS path based on the repositoryId and binding.
*
* @author steveglover
*
*/
public interface PathGenerator
{
public void generatePath(HttpServletRequest req, StringBuilder url, String repositoryId, Binding binding);
}

View File

@@ -0,0 +1,101 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.opencmis;
import javax.servlet.http.HttpServletRequest;
/**
* Generates an OpenCMIS base url based on the request, repository id and binding. The url scheme, host and port
* are overridden by any proxy http header parameters, if present.
*
* @author steveglover
*
*/
public class ProxyBaseUrlGenerator extends AbstractBaseUrlGenerator
{
public static final String FORWARDED_HOST_HEADER = "X-Forwarded-Host";
public static final String FORWARDED_PROTO_HEADER = "X-Forwarded-Proto";
public static final String HTTPS_SCHEME = "https";
public static final String HTTP_SCHEME = "http";
@Override
protected String getServerPath(HttpServletRequest request)
{
String scheme = request.getHeader(FORWARDED_PROTO_HEADER);
String serverName;
int serverPort;
if (!HTTP_SCHEME.equalsIgnoreCase(scheme) && !HTTPS_SCHEME.equalsIgnoreCase(scheme))
{
scheme = request.getScheme();
}
serverName = request.getServerName();
serverPort = request.getServerPort();
String host = request.getHeader(FORWARDED_HOST_HEADER);
if ((host != null) && (host.length() > 0))
{
int index = host.indexOf(':');
if (index < 0)
{
serverName = host;
serverPort = getDefaultPort(scheme);
}
else
{
serverName = host.substring(0, index);
try
{
serverPort = Integer.parseInt(host.substring(index + 1));
}
catch (NumberFormatException e)
{
serverPort = getDefaultPort(scheme);
}
}
}
StringBuilder sb = new StringBuilder();
sb.append(scheme);
sb.append("://");
sb.append(serverName);
sb.append(":");
sb.append(serverPort);
return sb.toString();
}
private int getDefaultPort(String scheme)
{
if (HTTPS_SCHEME.equalsIgnoreCase(scheme))
{
return 443;
}
return 80;
}
}

View File

@@ -0,0 +1,225 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.opencmis;
import java.util.ArrayList;
import java.util.List;
import org.alfresco.query.PagingRequest;
import org.alfresco.query.PagingResults;
import org.alfresco.repo.tenant.Network;
import org.alfresco.repo.tenant.NetworksService;
import org.alfresco.repo.tenant.TenantAdminService;
import org.alfresco.repo.tenant.TenantService;
import org.alfresco.repo.tenant.TenantUtil;
import org.alfresco.repo.tenant.TenantUtil.TenantRunAsWork;
import org.alfresco.util.FileFilterMode;
import org.alfresco.util.FileFilterMode.Client;
import org.apache.chemistry.opencmis.commons.data.Acl;
import org.apache.chemistry.opencmis.commons.data.ContentStream;
import org.apache.chemistry.opencmis.commons.data.ExtensionsData;
import org.apache.chemistry.opencmis.commons.data.Properties;
import org.apache.chemistry.opencmis.commons.data.RepositoryInfo;
import org.apache.chemistry.opencmis.commons.enums.VersioningState;
import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.RepositoryInfoImpl;
import org.apache.chemistry.opencmis.commons.spi.Holder;
/**
* Override OpenCMIS service object - for public api
*
* @author sglover
* @since PublicApi1.0
*/
public class PublicApiAlfrescoCmisService extends AlfrescoCmisServiceImpl
{
protected CMISConnector connector;
protected TenantAdminService tenantAdminService;
protected NetworksService networksService;
public PublicApiAlfrescoCmisService(CMISConnector connector, TenantAdminService tenantAdminService, NetworksService networksService)
{
super(connector);
this.connector = connector;
this.networksService = networksService;
this.tenantAdminService = tenantAdminService;
}
@Override
public String create(String repositoryId, Properties properties, String folderId,
ContentStream contentStream, VersioningState versioningState,
List<String> policies, ExtensionsData extension)
{
FileFilterMode.setClient(Client.cmis);
try
{
return super.create(
repositoryId,
properties,
folderId,
contentStream,
versioningState,
policies,
extension);
}
finally
{
FileFilterMode.clearClient();
}
}
/**
* Overridden to capture content upload for publishing to analytics service.
*/
@Override
public String createDocument(String repositoryId, Properties properties, String folderId,
ContentStream contentStream, VersioningState versioningState,
List<String> policies, Acl addAces, Acl removeAces, ExtensionsData extension)
{
String newId = super.createDocument(
repositoryId,
properties,
folderId,
contentStream,
versioningState,
policies,
addAces,
removeAces,
extension);
return newId;
}
/**
* Overridden to capture content upload for publishing to analytics service.
*/
@Override
public void setContentStream(String repositoryId, Holder<String> objectId,
Boolean overwriteFlag, Holder<String> changeToken, ContentStream contentStream,
ExtensionsData extension)
{
FileFilterMode.setClient(Client.cmis);
try
{
super.setContentStream(repositoryId, objectId, overwriteFlag, changeToken, contentStream, extension);
}
finally
{
FileFilterMode.clearClient();
}
}
@Override
public List<RepositoryInfo> getRepositoryInfos(ExtensionsData extension)
{
// for currently authenticated user
PagingResults<Network> networks = networksService.getNetworks(new PagingRequest(0, Integer.MAX_VALUE));
List<Network> page = networks.getPage();
final List<RepositoryInfo> repoInfos = new ArrayList<RepositoryInfo>(page.size() + 1);
for (Network network : page)
{
repoInfos.add(getRepositoryInfo(network));
}
return repoInfos;
}
@Override
public RepositoryInfo getRepositoryInfo(String repositoryId, ExtensionsData extension)
{
Network network = null;
try
{
checkRepositoryId(repositoryId);
network = networksService.getNetwork(repositoryId);
}
catch(Exception e)
{
// ACE-2540: Avoid information leak. Same response if repository does not exist or if user is not a member
throw new CmisObjectNotFoundException("Unknown repository '" + repositoryId + "'!");
}
return getRepositoryInfo(network);
}
private RepositoryInfo getRepositoryInfo(final Network network)
{
final String networkId = network.getTenantDomain();
final String tenantDomain = (networkId.equals(TenantUtil.SYSTEM_TENANT) || networkId.equals(TenantUtil.DEFAULT_TENANT)) ? TenantService.DEFAULT_DOMAIN : networkId;
return TenantUtil.runAsSystemTenant(new TenantRunAsWork<RepositoryInfo>()
{
public RepositoryInfo doWork()
{
RepositoryInfoImpl repoInfo = (RepositoryInfoImpl)connector.getRepositoryInfo(getContext().getCmisVersion());
repoInfo.setId(!networkId.equals("") ? networkId : TenantUtil.SYSTEM_TENANT);
repoInfo.setName(tenantDomain);
repoInfo.setDescription(tenantDomain);
return repoInfo;
}
}, tenantDomain);
}
@Override
public void checkRepositoryId(String repositoryId)
{
if(repositoryId.equals(TenantUtil.DEFAULT_TENANT) || repositoryId.equals(TenantUtil.SYSTEM_TENANT))
{
// TODO check for super admin
return;
}
if(!tenantAdminService.existsTenant(repositoryId) || !tenantAdminService.isEnabledTenant(repositoryId))
{
throw new CmisObjectNotFoundException("Unknown repository '" + repositoryId + "'!");
}
}
@Override
public void beforeCall()
{
// NOTE: Don't invoke super beforeCall to exclude authentication which is already supported by
// Web Script F/W
//super.beforeCall();
}
@Override
public void afterCall()
{
// NOTE: Don't invoke super afterCall to exclude authentication which is already supported by
// Web Script F/W
//super.afterCall();
}
@Override
public void close()
{
super.close();
}
}

View File

@@ -0,0 +1,58 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.opencmis;
import org.alfresco.repo.tenant.NetworksService;
import org.alfresco.repo.tenant.TenantAdminService;
/**
* Override factory for OpenCMIS service objects - for public api
*
* @author steveglover
* @author janv
* @since PublicApi1.0
*/
public class PublicApiAlfrescoCmisServiceFactory extends AlfrescoCmisServiceFactory
{
private TenantAdminService tenantAdminService;
private NetworksService networksService;
public void setNetworksService(NetworksService networksService)
{
this.networksService = networksService;
}
public void setTenantAdminService(TenantAdminService tenantAdminService)
{
this.tenantAdminService = tenantAdminService;
}
@Override
protected AlfrescoCmisService getCmisServiceTarget(CMISConnector connector)
{
return new PublicApiAlfrescoCmisService(connector, tenantAdminService, networksService);
}
}

View File

@@ -0,0 +1,46 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.opencmis;
import org.springframework.extensions.webscripts.WebScriptRequest;
/**
* Dispatches OpenCMIS requests to the OpenCMIS AtomPub servlet.
*
* @author steveglover
*
*/
public class PublicApiAtomPubCMISDispatcher extends AtomPubCMISDispatcher
{
@Override
protected CMISHttpServletRequest getHttpRequest(WebScriptRequest req)
{
String serviceName = getServiceName();
CMISHttpServletRequest httpReqWrapper = new PublicApiCMISHttpServletRequest(req, serviceName, baseUrlGenerator,
getBinding(), getCurrentDescriptor(), tenantAdminService);
return httpReqWrapper;
}
}

View File

@@ -0,0 +1,46 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.opencmis;
import org.springframework.extensions.webscripts.WebScriptRequest;
/**
* Cloud-specific browser binding OpenCMIS dispatcher.
*
* @author steveglover
*
*/
public class PublicApiBrowserCMISDispatcher extends BrowserCMISDispatcher
{
@Override
protected CMISHttpServletRequest getHttpRequest(WebScriptRequest req)
{
String serviceName = getServiceName();
CMISHttpServletRequest httpReqWrapper = new PublicApiCMISHttpServletRequest(req, serviceName,
baseUrlGenerator, getBinding(), getCurrentDescriptor(), tenantAdminService);
return httpReqWrapper;
}
}

View File

@@ -0,0 +1,67 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.opencmis;
import java.util.Map;
import org.alfresco.opencmis.CMISDispatcherRegistry.Binding;
import org.alfresco.repo.tenant.TenantAdminService;
import org.alfresco.service.descriptor.Descriptor;
import org.springframework.extensions.webscripts.Match;
import org.springframework.extensions.webscripts.WebScriptRequest;
/**
* Wraps an OpenCMIS HttpServletRequest, mapping urls and adding servlet attributes specific to the Alfresco implementation of OpenCMIS.
*/
public class PublicApiCMISHttpServletRequest extends CMISHttpServletRequest
{
public PublicApiCMISHttpServletRequest(WebScriptRequest req, String serviceName, BaseUrlGenerator baseUrlGenerator,
Binding binding, Descriptor currentDescriptor, TenantAdminService tenantAdminService)
{
super(req, serviceName, baseUrlGenerator, binding, currentDescriptor, tenantAdminService);
}
protected void addAttributes()
{
super.addAttributes();
Match match = req.getServiceMatch();
Map<String, String> templateVars = match.getTemplateVars();
String apiScope = templateVars.get("apiScope");
String apiVersion = templateVars.get("apiVersion");
if(apiScope != null)
{
httpReq.setAttribute("apiScope", apiScope);
}
if(apiVersion != null)
{
httpReq.setAttribute("apiVersion", apiVersion);
}
}
}

View File

@@ -0,0 +1,63 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.opencmis;
import javax.servlet.http.HttpServletRequest;
import org.alfresco.opencmis.CMISDispatcherRegistry.Binding;
/**
* Cloud generator for OpenCMIS paths based on the repositoryId and binding.
*
* @author steveglover
*
*/
public class PublicApiPathGenerator implements PathGenerator
{
public void generatePath(HttpServletRequest req, StringBuilder url, String repositoryId, Binding binding)
{
url.append("{repositoryId}");
url.append("/");
String scope = (String)req.getAttribute("apiScope");
String serviceName = (String)req.getAttribute("serviceName");
String apiVersion = (String)req.getAttribute("apiVersion");
if(scope == null)
{
scope = "public";
}
url.append(scope);
url.append("/");
url.append(serviceName);
url.append("/");
url.append("versions");
url.append("/");
url.append(apiVersion);
url.append("/");
url.append(binding.toString());
}
}

View File

@@ -0,0 +1,90 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.opencmis;
import javax.servlet.http.HttpServletRequest;
import org.alfresco.repo.admin.SysAdminParams;
/**
* Generates an OpenCMIS base url based on the request, repository id and binding. The url scheme, host and port
* are overridden by sys admin parameters.
*
* @author steveglover
*
*/
public class SysAdminParamsBaseUrlGenerator extends AbstractBaseUrlGenerator
{
private SysAdminParams sysAdminParams;
protected String getServerPath(HttpServletRequest request)
{
StringBuilder sb = new StringBuilder();
sb.append(getServerScheme(request));
sb.append("://");
sb.append(getServerName(request));
sb.append(":");
sb.append(getServerPort(request));
return sb.toString();
}
protected String getServerScheme(HttpServletRequest request)
{
String scheme = sysAdminParams.getAlfrescoProtocol();
if (scheme == null)
{
scheme = request.getScheme();
}
scheme = request.getScheme();
return scheme;
}
protected String getServerName(HttpServletRequest request)
{
String hostname = sysAdminParams.getAlfrescoHost();
if (hostname == null)
{
hostname = request.getScheme();
}
hostname = request.getServerName();
return hostname;
}
protected int getServerPort(HttpServletRequest request)
{
Integer port = sysAdminParams.getAlfrescoPort();
if (port == null)
{
port = request.getServerPort();
}
if (port == null)
{
port = request.getServerPort();
}
return port;
}
}

View File

@@ -0,0 +1,51 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo;
import java.io.Serializable;
/**
* Contract implemented by any object that represents an Alfresco "user" that
* can be persisted in an HTTP Session.
*
* @author Kevin Roast
*/
public interface SessionUser extends Serializable
{
/**
* Return the user name
*
* @return user name
*/
String getUserName();
/**
* Return the ticket
*
* @return ticket
*/
String getTicket();
}

View File

@@ -0,0 +1,71 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.imap.scripts;
import java.io.IOException;
import org.alfresco.repo.imap.ImapService;
import org.alfresco.repo.management.subsystems.ChildApplicationContextFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.extensions.webscripts.AbstractWebScript;
import org.springframework.extensions.webscripts.WebScriptRequest;
import org.springframework.extensions.webscripts.WebScriptResponse;
/**
* Shows the availability of the IMAP server via web script request.
*/
public class ServerStatusWebScript extends AbstractWebScript implements ApplicationContextAware
{
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
this.applicationContext = applicationContext;
}
public void execute(WebScriptRequest req, WebScriptResponse res) throws IOException
{
ChildApplicationContextFactory subsystem = (ChildApplicationContextFactory)applicationContext.getBean("imap");
// note: getting property (rather than getting imapService bean to check isEnabled) does not cause subsystem startup (if stopped)
// hence providing ability for subsystem to be disabled (whilst still supporting ability to check status and/or dynamically start via JMX)
String isEnabled = (String)subsystem.getProperty("imap.server.enabled");
if (new Boolean(isEnabled).booleanValue())
{
res.getWriter().write("enabled");
}
else
{
res.getWriter().write("disabled");
}
res.getWriter().flush();
res.getWriter().close();
}
}

View File

@@ -0,0 +1,102 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.surf.policy;
import java.util.List;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.node.NodeServicePolicies.BeforeDeleteNodePolicy;
import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.repo.web.scripts.bean.ADMRemoteStore;
import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.repository.NodeRef;
/**
* Delete Node Policy to remove surf-config files for a deleted user.
*
* @author Dmitry Velichkevich
* @author Kevin Roast
*/
public class SurfConfigCleaner extends ADMRemoteStore implements BeforeDeleteNodePolicy
{
private PolicyComponent policyComponent;
public void init()
{
this.policyComponent.bindClassBehaviour(
BeforeDeleteNodePolicy.QNAME,
ContentModel.TYPE_PERSON,
new JavaBehaviour(this, BeforeDeleteNodePolicy.QNAME.getLocalName()));
}
@Override
public void beforeDeleteNode(NodeRef nodeRef)
{
final String userName = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_USERNAME);
final NodeRef componentsRef = getGlobalComponentsNodeRef();
final NodeRef usersFolderRef = getGlobalUserFolderNodeRef();
// Remove the user Surf config folder, contains dynamic page definitions such as dashboard.xml
// For example, qname path to user folder:
// /app:company_home/st:sites/cm:surf-config/cm:pages/cm:user/cm:admin
// ^^^^^ encoded username
if (usersFolderRef != null)
{
NodeRef userFolderNodeRef = nodeService.getChildByName(usersFolderRef, ContentModel.ASSOC_CONTAINS, encodePath(userName));
if (userFolderNodeRef != null)
{
// CLOUD-2053: Need to set as temporary to delete node instead of archiving.
nodeService.addAspect(userFolderNodeRef, ContentModel.ASPECT_TEMPORARY, null);
nodeService.deleteNode(userFolderNodeRef);
}
}
// Remove each component Surf config file related to the user, such as the dashboard dashlet component references
// For example, qname path to user component file:
// /app:company_home/st:sites/cm:surf-config/cm:components/cm:page.component-1-1.user~admin~dashboard.xml
// ^^^^^ encoded username
if (componentsRef != null)
{
List<FileInfo> configNodes = getFileNodes(
fileFolderService.getFileInfo(componentsRef),
buildUserConfigSearchPattern(userName),
true).getPage();
for (FileInfo fileInfo : configNodes)
{
// CLOUD-2053: Need to set as temporary to delete node instead of archiving.
nodeService.addAspect(fileInfo.getNodeRef(), ContentModel.ASPECT_TEMPORARY, null);
nodeService.deleteNode(fileInfo.getNodeRef());
}
}
}
public void setPolicyComponent(PolicyComponent policyComponent)
{
this.policyComponent = policyComponent;
}
}

View File

@@ -0,0 +1,51 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.auth;
/**
* AuthenticationListener implementations can receive notifications of successful and unsuccessful
* authentication requests, made during web script, WebDav or Sharepoint requests.
*
* @author Alex Miller
*/
public interface AuthenticationListener
{
/**
* A user was successfully authenticated credentials.
*/
public void userAuthenticated(WebCredentials credentials);
/**
* An authentication attempt, using credentials, failed with exception, ex.
*/
public void authenticationFailed(WebCredentials credentials, Exception ex);
/**
* An authentication attempt, using credentials, failed.
*/
public void authenticationFailed(WebCredentials credentials);
}

View File

@@ -0,0 +1,81 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.auth;
import org.apache.commons.codec.digest.DigestUtils;
/**
* {@link WebCredentials} holding username and the md5 hash of the password.
*
* @author Alex Miller
*/
public class BasicAuthCredentials implements WebCredentials
{
private static final long serialVersionUID = 2626445241420904072L;
private String userName;
private String password;
/**
* Default constructor
*/
public BasicAuthCredentials(String userName, String password)
{
this.userName = userName;
this.password = DigestUtils.md5Hex(password);
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((this.password == null) ? 0 : this.password.hashCode());
result = prime * result + ((this.userName == null) ? 0 : this.userName.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj) { return true; }
if (obj == null) { return false; }
if (getClass() != obj.getClass()) { return false; }
BasicAuthCredentials other = (BasicAuthCredentials) obj;
if (this.password == null)
{
if (other.password != null) { return false; }
}
else if (!this.password.equals(other.password)) { return false; }
if (this.userName == null)
{
if (other.userName != null) { return false; }
}
else if (!this.userName.equals(other.userName)) { return false; }
return true;
}
}

View File

@@ -0,0 +1,51 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.auth;
/**
* {@link WebCredentials} representing a guest user.
*
* @author Alex Miller
*/
public class GuestCredentials implements WebCredentials
{
private static final long serialVersionUID = 1L;
@Override
public boolean equals(Object obj)
{
return getClass().equals(obj.getClass());
}
@Override
public int hashCode()
{
return getClass().hashCode();
}
}

View File

@@ -0,0 +1,52 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.auth;
import org.alfresco.jlan.server.auth.spnego.NegTokenInit;
import org.alfresco.jlan.server.auth.spnego.NegTokenTarg;
/**
* {@link WebCredentials} implementation for holding Kerberos credentials.
*/
public class KerberosCredentials implements WebCredentials
{
private static final long serialVersionUID = 4625258932647351551L;
private NegTokenInit negToken;
private NegTokenTarg negTokenTarg;
public KerberosCredentials(NegTokenInit negToken, NegTokenTarg negTokenTarg)
{
this.negToken = negToken;
this.negTokenTarg = negTokenTarg;
}
public KerberosCredentials(NegTokenInit negToken)
{
this.negToken = negToken;
}
}

View File

@@ -0,0 +1,54 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.auth;
/**
* {@link AuthenticationListener} that does nothing.
*
* @author Alex Miller
*/
public class NoopAuthenticationListener implements AuthenticationListener
{
@Override
public void userAuthenticated(WebCredentials credentials)
{
// Noop
}
@Override
public void authenticationFailed(WebCredentials credentials)
{
// Noop
}
@Override
public void authenticationFailed(WebCredentials credentials, Exception ex)
{
// Noop
}
}

View File

@@ -0,0 +1,38 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.auth;
public interface TenantAuthentication
{
/**
* Authenticate user against tenant
*
* @param username String
* @param tenant String
* @return true => authenticated, false => not authenticated
*/
boolean authenticateTenant(String username, String tenant);
}

View File

@@ -0,0 +1,68 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.auth;
/**
* {@link WebCredentials} class for holding Alfresco tickets.
*
* @author Alex Miller
*/
public class TicketCredentials implements WebCredentials
{
private static final long serialVersionUID = -8255499275655719748L;
private String ticket;
public TicketCredentials(String ticket)
{
this.ticket = ticket;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((this.ticket == null) ? 0 : this.ticket.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj) { return true; }
if (obj == null) { return false; }
if (getClass() != obj.getClass()) { return false; }
TicketCredentials other = (TicketCredentials) obj;
if (this.ticket == null)
{
if (other.ticket != null) { return false; }
}
else if (!this.ticket.equals(other.ticket)) { return false; }
return true;
}
}

View File

@@ -0,0 +1,51 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.auth;
/**
* {@link WebCredentials} where credentials are undetermined.
*
* @author Alex Miller
*/
public class UnknownCredentials implements WebCredentials
{
private static final long serialVersionUID = 1L;
@Override
public boolean equals(Object obj)
{
return getClass().equals(obj.getClass());
}
@Override
public int hashCode()
{
return getClass().hashCode();
}
}

View File

@@ -0,0 +1,40 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.auth;
import java.io.Serializable;
/**
* WebScriptCredentials interface.
*
* Passed to {@link AuthenticationListener}s with credentials used in an authentication attempt.
*
* @author Alex Miller
*/
public interface WebCredentials extends Serializable
{
}

View File

@@ -0,0 +1,91 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.filter.beans;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
/**
* An adapter from the servlet filter world into the Spring dependency injected world. Simply looks up a
* {@link DependencyInjectedFilter} with a configured bean name and delegates the
* {@link #doFilter(ServletRequest, ServletResponse, FilterChain)} call to that. This allows us to swap in and out
* different implementations for different 'hook points' in web.xml.
*
* @author dward
*/
public class BeanProxyFilter implements Filter
{
/**
* Name of the init parameter that carries the proxied bean name
*/
private static final String INIT_PARAM_BEAN_NAME = "beanName";
private DependencyInjectedFilter filter;
private ServletContext context;
/**
* Initialize the filter.
*
* @param args
* FilterConfig
* @throws ServletException
* the servlet exception
* @exception ServletException
*/
public void init(FilterConfig args) throws ServletException
{
WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(args.getServletContext());
this.filter = (DependencyInjectedFilter)ctx.getBean(args.getInitParameter(INIT_PARAM_BEAN_NAME));
this.context = args.getServletContext();
}
/* (non-Javadoc)
* @see javax.servlet.Filter#destroy()
*/
public void destroy()
{
this.filter = null;
}
/* (non-Javadoc)
* @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
ServletException
{
this.filter.doFilter(this.context, request, response, chain);
}
}

View File

@@ -0,0 +1,63 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.filter.beans;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
* A bean-like equivalent of a servlet filter, designed to be managed by a Spring container.
*
* @see BeanProxyFilter
* @author dward
*/
public interface DependencyInjectedFilter
{
/**
* The <code>doFilter</code> method of the Filter is called by the container each time a request/response pair is
* passed through the chain due to a client request for a resource at the end of the chain. The FilterChain passed
* in to this method allows the Filter to pass on the request and response to the next entity in the chain.
* <p>
* A typical implementation of this method would follow the following pattern:- <br>
* 1. Examine the request<br>
* 2. Optionally wrap the request object with a custom implementation to filter content or headers for input
* filtering <br>
* 3. Optionally wrap the response object with a custom implementation to filter content or headers for output
* filtering <br>
* 4. a) <strong>Either</strong> invoke the next entity in the chain using the FilterChain object (
* <code>chain.doFilter()</code>), <br>
* 4. b) <strong>or</strong> not pass on the request/response pair to the next entity in the filter chain to block
* the request processing<br>
* 5. Directly set headers on the response after invocation of the next entity in the filter chain.
**/
public void doFilter(ServletContext context, ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
ServletException;
}

View File

@@ -0,0 +1,79 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.filter.beans;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.alfresco.repo.management.subsystems.ActivateableBean;
/**
* A Benign filter that does nothing more than invoke the filter chain. Allows strategic points of the filter chain to
* be configured in and out according to the authentication subsystem in use.
*
* @author dward
*/
public class NullFilter implements DependencyInjectedFilter, ActivateableBean
{
private boolean isActive = true;
/**
* Activates or deactivates the bean
*
* @param active
* <code>true</code> if the bean is active and initialization should complete
*/
public void setActive(boolean active)
{
this.isActive = active;
}
/* (non-Javadoc)
* @see org.alfresco.repo.management.subsystems.ActivateableBean#isActive()
*/
public boolean isActive()
{
return this.isActive;
}
/*
* (non-Javadoc)
* @see org.alfresco.repo.web.filter.beans.DependencyInjectedFilter#doFilter(javax.servlet.ServletContext,
* javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
*/
public void doFilter(ServletContext context, ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException
{
chain.doFilter(request, response);
}
}

View File

@@ -0,0 +1,83 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.filter.beans;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/**
* A filter that will use the HttpSession (if it exists) as the monitor for a
* synchronized block so that only one request per session is processed at any
* time.
*
* Originally created to avoid having to make 200+ JSF session scoped beans thread
* safe.
*
* @author Alan Davis
* @deprecated 5.0 not exposed in web-client web.xml
*/
public class SessionSynchronizedFilter implements Filter
{
@Override
public void init(FilterConfig arg0) throws ServletException
{
}
@Override
public void destroy()
{
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException
{
HttpSession session = null;
if (request instanceof HttpServletRequest)
{
session = ((HttpServletRequest)request).getSession(false);
}
if (session != null)
{
synchronized(session)
{
chain.doFilter(request, response);
}
}
else
{
chain.doFilter(request, response);
}
}
}

View File

@@ -0,0 +1,96 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mozilla.javascript.ContextFactory;
import org.mozilla.javascript.tools.debugger.Dim;
import org.mozilla.javascript.tools.debugger.SwingGui;
import org.springframework.extensions.webscripts.ScriptDebugger;
/**
* Alfresco implementation of Rhino JavaScript debugger
*
* Provides support for authenticated access to object inspection.
*
* @author davidc
*/
public class AlfrescoRhinoScriptDebugger extends ScriptDebugger
{
private static final Log logger = LogFactory.getLog(AlfrescoRhinoScriptDebugger.class);
// Logger
private ContextFactory factory = null;
private SwingGui gui = null;
@Override
protected void initDebugger()
{
dim = new AlfrescoDim();
}
@Override
public void start()
{
if (logger.isDebugEnabled())
{
activate();
show();
}
}
@Override
protected String getTitle()
{
return "Alfresco Repository JavaScript Debugger";
}
public static class AlfrescoDim extends Dim
{
/* (non-Javadoc)
* @see org.mozilla.javascript.tools.debugger.Dim#objectToString(java.lang.Object)
*/
@Override
public String objectToString(final Object arg0)
{
// execute command in context of currently selected user
return AuthenticationUtil.runAs(new RunAsWork<String>()
{
@SuppressWarnings("synthetic-access")
public String doWork() throws Exception
{
return AlfrescoDim.super.objectToString(arg0);
}
}, AuthenticationUtil.getSystemUserName());
}
}
}

View File

@@ -0,0 +1,50 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2018 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.springframework.extensions.webscripts.servlet.WebScriptServlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class AlfrescoWebScriptServlet extends WebScriptServlet
{
@Override
protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException
{
try
{
super.service(req, res);
}
finally
{
AuthenticationUtil.clearCurrentSecurityContext();
}
}
}

View File

@@ -0,0 +1,405 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.springframework.extensions.surf.util.Content;
import org.springframework.extensions.webscripts.Description.FormatStyle;
import org.springframework.extensions.webscripts.Match;
import org.springframework.extensions.webscripts.Runtime;
import org.springframework.extensions.webscripts.WebScriptRequest;
import org.springframework.extensions.webscripts.WrappingWebScriptRequest;
import org.springframework.util.FileCopyUtils;
public class BufferedRequest implements WrappingWebScriptRequest
{
private TempOutputStreamFactory streamFactory;
private WebScriptRequest req;
private TempOutputStream bufferStream;
private InputStream contentStream;
private BufferedReader contentReader;
public BufferedRequest(WebScriptRequest req, TempOutputStreamFactory streamFactory)
{
this.req = req;
this.streamFactory = streamFactory;
}
private TempOutputStream getBufferedBodyAsTempStream() throws IOException
{
if (bufferStream == null)
{
bufferStream = streamFactory.createOutputStream();
try
{
// Copy the stream
FileCopyUtils.copy(req.getContent().getInputStream(), bufferStream);
}
catch (IOException e)
{
bufferStream.destroy();
throw e;
}
}
return bufferStream;
}
private InputStream bufferInputStream() throws IOException
{
if (contentReader != null)
{
throw new IllegalStateException("Reader in use");
}
if (contentStream == null)
{
contentStream = getBufferedBodyAsTempStream().getInputStream();
}
return contentStream;
}
public void reset()
{
if (contentStream != null)
{
try
{
contentStream.close();
}
catch (Exception e)
{
}
contentStream = null;
}
if (contentReader != null)
{
try
{
contentReader.close();
}
catch (Exception e)
{
}
contentReader = null;
}
}
public void close()
{
reset();
if (bufferStream != null)
{
try
{
bufferStream.destroy();
}
catch (Exception e)
{
}
bufferStream = null;
}
}
/* (non-Javadoc)
* @see org.springframework.extensions.webscripts.WrappingWebScriptRequest#getNext()
*/
@Override
public WebScriptRequest getNext()
{
return req;
}
/* (non-Javadoc)
* @see org.springframework.extensions.webscripts.WebScriptRequest#forceSuccessStatus()
*/
@Override
public boolean forceSuccessStatus()
{
return req.forceSuccessStatus();
}
/* (non-Javadoc)
* @see org.springframework.extensions.webscripts.WebScriptRequest#getAgent()
*/
@Override
public String getAgent()
{
return req.getAgent();
}
/* (non-Javadoc)
* @see org.springframework.extensions.webscripts.WebScriptRequest#getContent()
*/
@Override
public Content getContent()
{
final Content wrapped = req.getContent();
return new Content(){
@Override
public String getContent() throws IOException
{
return wrapped.getContent();
}
@Override
public String getEncoding()
{
return wrapped.getEncoding();
}
@Override
public String getMimetype()
{
return wrapped.getMimetype();
}
@Override
public long getSize()
{
return wrapped.getSize();
}
@Override
public InputStream getInputStream()
{
if (BufferedRequest.this.contentReader != null)
{
throw new IllegalStateException("Reader in use");
}
if (BufferedRequest.this.contentStream == null)
{
try
{
BufferedRequest.this.contentStream = bufferInputStream();
}
catch (IOException e)
{
throw new RuntimeException(e);
}
}
return BufferedRequest.this.contentStream;
}
@Override
public BufferedReader getReader() throws IOException
{
if (BufferedRequest.this.contentStream != null)
{
throw new IllegalStateException("Input Stream in use");
}
if (BufferedRequest.this.contentReader == null)
{
String encoding = wrapped.getEncoding();
InputStream in = bufferInputStream();
BufferedRequest.this.contentReader = new BufferedReader(new InputStreamReader(in, encoding == null ? "ISO-8859-1" : encoding));
}
return BufferedRequest.this.contentReader;
}
};
}
/* (non-Javadoc)
* @see org.springframework.extensions.webscripts.WebScriptRequest#getContentType()
*/
@Override
public String getContentType()
{
return req.getContentType();
}
/* (non-Javadoc)
* @see org.springframework.extensions.webscripts.WebScriptRequest#getContextPath()
*/
@Override
public String getContextPath()
{
return req.getContextPath();
}
/* (non-Javadoc)
* @see org.springframework.extensions.webscripts.WebScriptRequest#getExtensionPath()
*/
@Override
public String getExtensionPath()
{
return req.getExtensionPath();
}
/* (non-Javadoc)
* @see org.springframework.extensions.webscripts.WebScriptRequest#getFormat()
*/
@Override
public String getFormat()
{
return req.getFormat();
}
/* (non-Javadoc)
* @see org.springframework.extensions.webscripts.WebScriptRequest#getFormatStyle()
*/
@Override
public FormatStyle getFormatStyle()
{
return req.getFormatStyle();
}
/* (non-Javadoc)
* @see org.springframework.extensions.webscripts.WebScriptRequest#getHeader(java.lang.String)
*/
@Override
public String getHeader(String name)
{
return req.getHeader(name);
}
/* (non-Javadoc)
* @see org.springframework.extensions.webscripts.WebScriptRequest#getHeaderNames()
*/
@Override
public String[] getHeaderNames()
{
return req.getHeaderNames();
}
/* (non-Javadoc)
* @see org.springframework.extensions.webscripts.WebScriptRequest#getHeaderValues(java.lang.String)
*/
@Override
public String[] getHeaderValues(String name)
{
return req.getHeaderValues(name);
}
/* (non-Javadoc)
* @see org.springframework.extensions.webscripts.WebScriptRequest#getJSONCallback()
*/
@Override
public String getJSONCallback()
{
return req.getJSONCallback();
}
/* (non-Javadoc)
* @see org.springframework.extensions.webscripts.WebScriptRequest#getParameter(java.lang.String)
*/
@Override
public String getParameter(String name)
{
return req.getParameter(name);
}
/* (non-Javadoc)
* @see org.springframework.extensions.webscripts.WebScriptRequest#getParameterNames()
*/
@Override
public String[] getParameterNames()
{
return req.getParameterNames();
}
/* (non-Javadoc)
* @see org.springframework.extensions.webscripts.WebScriptRequest#getParameterValues(java.lang.String)
*/
@Override
public String[] getParameterValues(String name)
{
return req.getParameterValues(name);
}
/* (non-Javadoc)
* @see org.springframework.extensions.webscripts.WebScriptRequest#getPathInfo()
*/
@Override
public String getPathInfo()
{
return req.getPathInfo();
}
/* (non-Javadoc)
* @see org.springframework.extensions.webscripts.WebScriptRequest#getQueryString()
*/
@Override
public String getQueryString()
{
return req.getQueryString();
}
/* (non-Javadoc)
* @see org.springframework.extensions.webscripts.WebScriptRequest#getRuntime()
*/
@Override
public Runtime getRuntime()
{
return req.getRuntime();
}
/* (non-Javadoc)
* @see org.springframework.extensions.webscripts.WebScriptRequest#getServerPath()
*/
@Override
public String getServerPath()
{
return req.getServerPath();
}
/* (non-Javadoc)
* @see org.springframework.extensions.webscripts.WebScriptRequest#getServiceContextPath()
*/
@Override
public String getServiceContextPath()
{
return req.getServiceContextPath();
}
/* (non-Javadoc)
* @see org.springframework.extensions.webscripts.WebScriptRequest#getServiceMatch()
*/
@Override
public Match getServiceMatch()
{
return req.getServiceMatch();
}
/* (non-Javadoc)
* @see org.springframework.extensions.webscripts.WebScriptRequest#getServicePath()
*/
@Override
public String getServicePath()
{
return req.getServicePath();
}
/* (non-Javadoc)
* @see org.springframework.extensions.webscripts.WebScriptRequest#getURL()
*/
@Override
public String getURL()
{
return req.getURL();
}
/* (non-Javadoc)
* @see org.springframework.extensions.webscripts.WebScriptRequest#isGuest()
*/
@Override
public boolean isGuest()
{
return req.isGuest();
}
/* (non-Javadoc)
* @see org.springframework.extensions.webscripts.WebScriptRequest#parseContent()
*/
@Override
public Object parseContent()
{
return req.parseContent();
}
}

View File

@@ -0,0 +1,281 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2019 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import org.alfresco.error.AlfrescoRuntimeException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.surf.util.StringBuilderWriter;
import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.Runtime;
import org.springframework.extensions.webscripts.WebScriptResponse;
import org.springframework.extensions.webscripts.WrappingWebScriptResponse;
import org.springframework.util.FileCopyUtils;
/**
* Transactional Buffered Response
*/
public class BufferedResponse implements WrappingWebScriptResponse
{
// Logger
protected static final Log logger = LogFactory.getLog(BufferedResponse.class);
private TempOutputStreamFactory streamFactory;
private WebScriptResponse res;
private int bufferSize;
private TempOutputStream outputStream = null;
private StringBuilderWriter outputWriter = null;
/**
* Construct
*
* @param res WebScriptResponse
* @param bufferSize int
*/
public BufferedResponse(WebScriptResponse res, int bufferSize, TempOutputStreamFactory streamFactory)
{
this.res = res;
this.bufferSize = bufferSize;
this.streamFactory = streamFactory;
}
/*
* (non-Javadoc)
* @see org.alfresco.web.scripts.WrappingWebScriptResponse#getNext()
*/
public WebScriptResponse getNext()
{
return res;
}
/*
* (non-Javadoc)
* @see org.alfresco.web.scripts.WebScriptResponse#addHeader(java.lang.String, java.lang.String)
*/
public void addHeader(String name, String value)
{
res.addHeader(name, value);
}
/*
* (non-Javadoc)
* @see org.alfresco.web.scripts.WebScriptResponse#encodeScriptUrl(java.lang.String)
*/
public String encodeScriptUrl(String url)
{
return res.encodeScriptUrl(url);
}
/*
* (non-Javadoc)
* @see org.alfresco.web.scripts.WebScriptResponse#getEncodeScriptUrlFunction(java.lang.String)
*/
public String getEncodeScriptUrlFunction(String name)
{
return res.getEncodeScriptUrlFunction(name);
}
/* (non-Javadoc)
* @see org.springframework.extensions.webscripts.WebScriptResponse#encodeResourceUrl(java.lang.String)
*/
public String encodeResourceUrl(String url)
{
return res.encodeResourceUrl(url);
}
/* (non-Javadoc)
* @see org.springframework.extensions.webscripts.WebScriptResponse#getEncodeResourceUrlFunction(java.lang.String)
*/
public String getEncodeResourceUrlFunction(String name)
{
return res.getEncodeResourceUrlFunction(name);
}
/*
* (non-Javadoc)
* @see org.alfresco.web.scripts.WebScriptResponse#getOutputStream()
*/
public OutputStream getOutputStream() throws IOException
{
if (outputStream == null)
{
if (outputWriter != null)
{
throw new AlfrescoRuntimeException("Already buffering output writer");
}
outputStream = streamFactory.createOutputStream();
}
return outputStream;
}
/*
* (non-Javadoc)
* @see org.alfresco.web.scripts.WebScriptResponse#getRuntime()
*/
public Runtime getRuntime()
{
return res.getRuntime();
}
/*
* (non-Javadoc)
* @see org.alfresco.web.scripts.WebScriptResponse#getWriter()
*/
public Writer getWriter() throws IOException
{
if (outputWriter == null)
{
if (outputStream != null)
{
throw new AlfrescoRuntimeException("Already buffering output stream");
}
outputWriter = new StringBuilderWriter(bufferSize);
}
return outputWriter;
}
/*
* (non-Javadoc)
* @see org.alfresco.web.scripts.WebScriptResponse#reset()
*/
public void reset()
{
if (outputStream != null)
{
outputStream = null;
}
else if (outputWriter != null)
{
outputWriter = null;
}
res.reset();
}
/* (non-Javadoc)
* @see org./alfresco.web.scripts.WebScriptResponse#resetjava.lang.String)
*/
public void reset(String preserveHeadersPattern)
{
if (outputStream != null)
{
outputStream = null;
}
else if (outputWriter != null)
{
outputWriter = null;
}
res.reset(preserveHeadersPattern);
}
/*
* (non-Javadoc)
* @see org.alfresco.web.scripts.WebScriptResponse#setCache(org.alfresco.web.scripts.Cache)
*/
public void setCache(Cache cache)
{
res.setCache(cache);
}
/*
* (non-Javadoc)
* @see org.alfresco.web.scripts.WebScriptResponse#setContentType(java.lang.String)
*/
public void setContentType(String contentType)
{
res.setContentType(contentType);
}
/*
* (non-Javadoc)
* @see org.alfresco.web.scripts.WebScriptResponse#setContentEncoding(java.lang.String)
*/
public void setContentEncoding(String contentEncoding)
{
res.setContentEncoding(contentEncoding);
}
/*
* (non-Javadoc)
* @see org.alfresco.web.scripts.WebScriptResponse#setHeader(java.lang.String, java.lang.String)
*/
public void setHeader(String name, String value)
{
res.setHeader(name, value);
}
/*
* (non-Javadoc)
* @see org.alfresco.web.scripts.WebScriptResponse#setStatus(int)
*/
public void setStatus(int status)
{
res.setStatus(status);
}
/**
* Write buffered response to underlying response
*/
public void writeResponse()
{
try
{
if (logger.isDebugEnabled() && outputStream != null)
{
logger.debug("Writing Transactional response: size=" + outputStream.getLength());
}
if (outputWriter != null)
{
outputWriter.flush();
res.getWriter().write(outputWriter.toString());
}
else if (outputStream != null)
{
if (logger.isDebugEnabled())
logger.debug("Writing Transactional response: size=" + outputStream.getLength());
try
{
outputStream.flush();
FileCopyUtils.copy(outputStream.getInputStream(), res.getOutputStream());
}
finally
{
outputStream.destroy();
}
}
}
catch (IOException e)
{
throw new AlfrescoRuntimeException("Failed to commit buffered response", e);
}
}
}

View File

@@ -0,0 +1,427 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.Pair;
import org.apache.commons.csv.CSVPrinter;
import org.apache.commons.csv.CSVFormat;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.ss.usermodel.Comment;
import org.apache.poi.ss.usermodel.Drawing;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.extensions.webscripts.DeclarativeWebScript;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.extensions.webscripts.WebScriptRequest;
import org.springframework.extensions.webscripts.WebScriptResponse;
/**
* Parent of Declarative Webscripts that generate Excel files,
* usually based on some sort of dictionary model.
*
* @author Nick Burch
*/
public abstract class DeclarativeSpreadsheetWebScript extends DeclarativeWebScript
{
public static final String MODEL_CSV = "csv";
public static final String MODEL_EXCEL = "excel";
public static final String PARAM_REQ_DELIMITER = "delimiter";
private CSVFormat csvFormat;
protected DictionaryService dictionaryService;
protected String filenameBase;
/**
* @param dictionaryService the DictionaryService to set
*/
public void setDictionaryService(DictionaryService dictionaryService)
{
this.dictionaryService = dictionaryService;
}
/**
* Identifies the resource for the webscript.
*/
protected abstract Object identifyResource(String format, WebScriptRequest req);
/**
* If the format is requested as HTML, should an exception be raised,
* or should an HTML version be called?
*/
protected abstract boolean allowHtmlFallback();
/**
* Returns the QNames of the model properties to be output in
* the header, and if they're required or not
*/
protected abstract List<Pair<QName, Boolean>> buildPropertiesForHeader(Object resource, String format, WebScriptRequest req);
/**
* Populates the body of the Excel Workbook, once the header has been
* output.
* This is called if the format is .xls or .xlsx
*/
protected abstract void populateBody(Object resource, Workbook workbook, Sheet sheet, List<QName> properties)
throws IOException;
/**
* Populates the body of the CSV file, once the header has been
* output.
* This is called if the format is .csv
*/
protected abstract void populateBody(Object resource, CSVPrinter csv, List<QName> properties)
throws IOException;
/**
* Set the CSVFormat
*
* @param csvFormat CSVFormat
*/
public void setCsvFormat(CSVFormat csvFormat)
{
this.csvFormat = csvFormat;
}
/**
* Get the CSVFormat. Returns {@link CSVFormat#EXCEL} if none was set.
*
* @return CSVFormat
*/
public CSVFormat getCsvFormat()
{
if (csvFormat == null)
{
return CSVFormat.EXCEL
.withQuote('"')
.withRecordSeparator("\n")
.withFirstRecordAsHeader();
}
else
{
return csvFormat;
}
}
/**
* @see org.springframework.extensions.webscripts.DeclarativeWebScript#executeImpl(org.springframework.extensions.webscripts.WebScriptRequest, org.springframework.extensions.webscripts.Status)
*/
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status)
{
Map<String, Object> model = new HashMap<String, Object>();
model.put("success", Boolean.TRUE);
// What format are they after?
String format = req.getFormat();
if("csv".equals(format) || "xls".equals(format) ||
"xlsx".equals(format) || "excel".equals(format))
{
// Identify the thing to process
Object resource = identifyResource(format, req);
// Generate the spreadsheet
try
{
generateSpreadsheet(resource, format, req, status, model);
return model;
}
catch(IOException e)
{
throw new WebScriptException(Status.STATUS_BAD_REQUEST,
"Unable to generate template file", e);
}
}
// If we get here, then it isn't a spreadsheet version
if(allowHtmlFallback())
{
// There's some sort of help / upload form
return model;
}
else
{
throw new WebScriptException("Web Script format '" + format + "' is not supported");
}
}
/**
* Generates the spreadsheet, based on the properties in the header
* and a callback for the body.
*/
public void generateSpreadsheet(Object resource, String format, WebScriptRequest req,
Status status, Map<String, Object> model) throws IOException
{
Pattern qnameMunger = Pattern.compile("([A-Z][a-z]+)([A-Z].*)");
String delimiterParam = req.getParameter(PARAM_REQ_DELIMITER);
CSVFormat reqCSVFormat = null;
if (delimiterParam != null && !delimiterParam.isEmpty())
{
reqCSVFormat = CSVFormat.EXCEL
.withDelimiter(delimiterParam.charAt(0))
.withQuote('"')
.withRecordSeparator("\n")
.withFirstRecordAsHeader();
}
// Build up the details of the header
List<Pair<QName, Boolean>> propertyDetails = buildPropertiesForHeader(resource, format, req);
String[] headings = new String[propertyDetails.size()];
String[] descriptions = new String[propertyDetails.size()];
boolean[] required = new boolean[propertyDetails.size()];
for(int i=0; i<headings.length; i++)
{
Pair<QName, Boolean> property = propertyDetails.get(i);
if(property == null || property.getFirst() == null)
{
headings[i] = "";
required[i] = false;
}
else
{
QName column = property.getFirst();
required[i] = property.getSecond();
// Ask the dictionary service nicely for the details
PropertyDefinition pd = dictionaryService.getProperty(column);
if(pd != null && pd.getTitle(dictionaryService) != null)
{
// Use the friendly titles, which may even be localised!
headings[i] = pd.getTitle(dictionaryService);
descriptions[i] = pd.getDescription(dictionaryService);
}
else
{
// Nothing friendly found, try to munge the raw qname into
// something we can show to a user...
String raw = column.getLocalName();
raw = raw.substring(0, 1).toUpperCase() + raw.substring(1);
Matcher m = qnameMunger.matcher(raw);
if(m.matches())
{
headings[i] = m.group(1) + " " + m.group(2);
}
else
{
headings[i] = raw;
}
}
}
}
// Build a list of just the properties
List<QName> properties = new ArrayList<QName>(propertyDetails.size());
for(Pair<QName,Boolean> p : propertyDetails)
{
QName qn = null;
if(p != null)
{
qn = p.getFirst();
}
properties.add(qn);
}
// Output
if("csv".equals(format))
{
StringWriter sw = new StringWriter();
CSVPrinter csv = new CSVPrinter(sw, reqCSVFormat != null ? reqCSVFormat : getCsvFormat());
csv.printRecord(headings);
populateBody(resource, csv, properties);
model.put(MODEL_CSV, sw.toString());
}
else
{
Workbook wb;
if("xlsx".equals(format))
{
wb = new XSSFWorkbook();
// TODO Properties
}
else
{
wb = new HSSFWorkbook();
// TODO Properties
}
// Add our header row
Sheet sheet = wb.createSheet("Export");
Row hr = sheet.createRow(0);
sheet.createFreezePane(0, 1);
Font fb = wb.createFont();
fb.setBold(true);
Font fi = wb.createFont();
fi.setBold(true);
fi.setItalic(true);
CellStyle csReq = wb.createCellStyle();
csReq.setFont(fb);
CellStyle csOpt = wb.createCellStyle();
csOpt.setFont(fi);
// Populate the header
Drawing draw = null;
for(int i=0; i<headings.length; i++)
{
Cell c = hr.createCell(i);
c.setCellValue(headings[i]);
if(required[i])
{
c.setCellStyle(csReq);
}
else
{
c.setCellStyle(csOpt);
}
if(headings[i].length() == 0)
{
sheet.setColumnWidth(i, 3*250);
}
else
{
sheet.setColumnWidth(i, 18*250);
}
if(descriptions[i] != null && descriptions[i].length() > 0)
{
// Add a description for it too
if(draw == null)
{
draw = sheet.createDrawingPatriarch();
}
ClientAnchor ca = wb.getCreationHelper().createClientAnchor();
ca.setCol1(c.getColumnIndex());
ca.setCol2(c.getColumnIndex()+1);
ca.setRow1(hr.getRowNum());
ca.setRow2(hr.getRowNum()+2);
Comment cmt = draw.createCellComment(ca);
cmt.setAuthor("");
cmt.setString(wb.getCreationHelper().createRichTextString(descriptions[i]));
cmt.setVisible(false);
c.setCellComment(cmt);
}
}
// Have the contents populated
populateBody(resource, wb, sheet, properties);
// Save it for the template
ByteArrayOutputStream baos = new ByteArrayOutputStream();
wb.write(baos);
model.put(MODEL_EXCEL, baos.toByteArray());
}
}
@Override
protected Map<String, Object> createTemplateParameters(WebScriptRequest req, WebScriptResponse res,
Map<String, Object> customParams)
{
Map<String, Object> model = super.createTemplateParameters(req, res, customParams);
// We sometimes need to monkey around to do the binary output...
model.put("req", req);
model.put("res", res);
model.put("writeExcel", new WriteExcel(res, model, req.getFormat(), filenameBase));
return model;
}
public static class WriteExcel
{
private String format;
private String filenameBase;
private WebScriptResponse res;
private Map<String, Object> model;
private WriteExcel(WebScriptResponse res, Map<String, Object> model, String format, String filenameBase)
{
this.res = res;
this.model = model;
this.format = format;
this.filenameBase = filenameBase;
}
public void write() throws IOException
{
String filename = filenameBase + "." + format;
// If it isn't a CSV, reset so we can send binary
if(! "csv".equals(format))
{
res.reset();
}
// Tell the browser it's a file download
res.addHeader("Content-Disposition", "attachment; filename=" + filename);
// Now send that data
if("csv".equals(format))
{
res.getWriter().append((String)model.get(MODEL_CSV));
}
else
{
// Set the mimetype, as we've reset
if("xlsx".equals(format))
{
res.setContentType(MimetypeMap.MIMETYPE_OPENXML_SPREADSHEET);
} else {
res.setContentType(MimetypeMap.MIMETYPE_EXCEL);
}
// Send the raw excel bytes
byte[] excel = (byte[])model.get(MODEL_EXCEL);
res.getOutputStream().write(excel);
}
}
}
}

View File

@@ -0,0 +1,869 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Element;
import org.springframework.extensions.config.ConfigImpl;
import org.springframework.extensions.config.ConfigSection;
import org.springframework.extensions.config.ConfigService;
import org.springframework.extensions.config.evaluator.Evaluator;
import org.springframework.extensions.config.xml.XMLConfigService;
import org.springframework.extensions.config.xml.elementreader.ConfigElementReader;
import org.springframework.extensions.surf.extensibility.BasicExtensionModule;
import org.springframework.extensions.surf.extensibility.ExtensibilityModel;
import org.springframework.extensions.surf.extensibility.HandlesExtensibility;
import org.springframework.extensions.surf.extensibility.WebScriptExtensibilityModuleHandler;
import org.springframework.extensions.surf.extensibility.impl.ExtensibilityModelImpl;
import org.springframework.extensions.surf.extensibility.impl.MarkupDirective;
import org.springframework.extensions.webscripts.Authenticator;
import org.springframework.extensions.webscripts.ExtendedScriptConfigModel;
import org.springframework.extensions.webscripts.ExtendedTemplateConfigModel;
import org.springframework.extensions.webscripts.ScriptConfigModel;
import org.springframework.extensions.webscripts.TemplateConfigModel;
import org.springframework.extensions.webscripts.WebScriptPropertyResourceBundle;
import org.springframework.extensions.webscripts.WebScriptRequest;
import org.springframework.extensions.webscripts.WebScriptResponse;
/**
* <p>A simple extensibility {@link org.springframework.extensions.webscripts.Container} for processing WebScripts. This extends the {@link RepositoryContainer} and
* implements the {@link HandlesExtensibility} interface to provide extensibility capabilities.</p>
*
* @author David Draper
*/
public class ExtensibilityContainer extends RepositoryContainer implements HandlesExtensibility
{
private static final Log logger = LogFactory.getLog(ExtensibilityContainer.class);
public boolean isExtensibilitySuppressed()
{
return false;
}
/**
* <p>Opens a new {@link ExtensibilityModel}, defers execution to the extended {@link RepositoryContainer} and
* then closes the {@link ExtensibilityModel}.</p>
*/
@Override
public void executeScript(WebScriptRequest scriptReq,
WebScriptResponse scriptRes,
Authenticator auth) throws IOException
{
ExtensibilityModel extModel = this.openExtensibilityModel();
try
{
super.executeScript(scriptReq, scriptRes, auth);
}
finally
{
// It's only necessary to close the model if it's actually been used. Not all WebScripts will make use of the
// model. An example of this would be the StreamContent WebScript. It is important not to attempt to close
// an unused model since the WebScript executed may have already flushed the response if it has overridden
// the default .execute() method.
if (this.modelUsed.get())
{
try
{
this.closeExtensibilityModel(extModel, scriptRes.getWriter());
}
catch (IOException e)
{
logger.error("An error occurred getting the Writer when closing an ExtensibilityModel", e);
}
}
}
}
/**
* <p>This keeps track of whether or not the {@link ExtensibilityModel} for the current thread has been used. The
* thread local value will only be set to <code>true</code> if the <code>getCurrentExtensibilityModel</code> method
* is called.</p>
*/
private ThreadLocal<Boolean> modelUsed = new ThreadLocal<Boolean>();
/**
* <p>A {@link WebScriptExtensibilityModuleHandler} is required for retrieving information on what
* {@link BasicExtensionModule} instances have been configured and the extension files that need
* to be processed. This variable should be set thorugh the Spring application context configuration.</p>
*/
private WebScriptExtensibilityModuleHandler extensibilityModuleHandler = null;
/**
* <p>Sets the {@link WebScriptExtensibilityModuleHandler} for this {@link org.springframework.extensions.webscripts.Container}.</p>
* @param extensibilityModuleHandler WebScriptExtensibilityModuleHandler
*/
public void setExtensibilityModuleHandler(WebScriptExtensibilityModuleHandler extensibilityModuleHandler)
{
this.extensibilityModuleHandler = extensibilityModuleHandler;
}
/**
* <p>Maintains a list of all the {@link ExtensibilityModel} instances being used across all the
* available threads.</p>
*/
private ThreadLocal<ExtensibilityModel> extensibilityModel = new ThreadLocal<ExtensibilityModel>();
/**
* <p>Creates a new {@link ExtensibilityModel} and sets it on the current thread</p>
*/
public ExtensibilityModel openExtensibilityModel()
{
if (logger.isDebugEnabled())
{
logger.debug("Opening for thread: " + Thread.currentThread().getName());
}
this.extendedBundleCache.set(new HashMap<String, WebScriptPropertyResourceBundle>());
this.evaluatedModules.set(null);
this.fileBeingProcessed.set(null);
this.globalConfig.set(null);
this.sections.set(null);
this.sectionsByArea.set(null);
ExtensibilityModel model = new ExtensibilityModelImpl(null, this);
this.extensibilityModel.set(model);
this.modelUsed.set(Boolean.FALSE);
return model;
}
/**
* <p>Flushes the {@link ExtensibilityModel} provided and sets its parent as the current {@link ExtensibilityModel}
* for the current thread.</p>
*/
public void closeExtensibilityModel(ExtensibilityModel model, Writer out)
{
if (logger.isDebugEnabled())
{
logger.debug("Closing for thread: " + Thread.currentThread().getName());
}
model.flushModel(out);
this.modelUsed.set(Boolean.FALSE);
this.extensibilityModel.set(null);
}
/**
* <p>Returns the {@link ExtensibilityModel} for the current thread.</p>
*/
public ExtensibilityModel getCurrentExtensibilityModel()
{
if (logger.isDebugEnabled())
{
logger.debug("Getting current for thread: " + Thread.currentThread().getName());
}
this.modelUsed.set(Boolean.TRUE);
return this.extensibilityModel.get();
}
/**
* <p>This method is implemented to perform no action as it is not necessary for a standalone WebScript
* container to add dependencies for processing.</p>
*/
public void updateExtendingModuleDependencies(String pathBeingProcessed, Map<String, Object> model)
{
// NOT REQUIRED FOR STANDALONE WEBSCRIPT CONTAINER
}
/**
* <p>A thread-safe cache of extended {@link ResourceBundle} instances for the current request.</p>
*/
private ThreadLocal<Map<String, WebScriptPropertyResourceBundle>> extendedBundleCache = new ThreadLocal<Map<String, WebScriptPropertyResourceBundle>>();
/**
* <p>Checks the cache to see if it has cached an extended bundle (that is a basic {@link ResourceBundle} that
* has had extension modules applied to it. Extended bundles can only be safely cached once per request as the modules
* applied can vary for each request.</p>
*
* @param webScriptId The id of the WebScript to retrieve the extended bundle for.
* @return A cached bundle or <code>null</code> if the bundle has not previously been cached.
*/
public ResourceBundle getCachedExtendedBundle(String webScriptId)
{
ResourceBundle cachedExtendedBundle = null;
Map<String, WebScriptPropertyResourceBundle> threadLocal = this.extendedBundleCache.get();
if (threadLocal != null)
{
cachedExtendedBundle = this.extendedBundleCache.get().get(webScriptId);
}
return cachedExtendedBundle;
}
/**
* <p>Adds a new extended bundle to the cache. An extended bundle is a WebScript {@link ResourceBundle} that has had
* {@link ResourceBundle} instances merged into it from extension modules that have been applied. These can only be cached
* for the lifetime of the request as different modules may be applied to the same WebScript for different requests.</p>
*
* @param webScriptId The id of the WebScript to cache the extended bundle against.
* @param extensionBundle The extended bundle to cache.
*/
public void addExtensionBundleToCache(String webScriptId, WebScriptPropertyResourceBundle extensionBundle)
{
Map<String, WebScriptPropertyResourceBundle> threadLocal = this.extendedBundleCache.get();
if (threadLocal == null)
{
// This should never be the case because when a new model is opened this value should be reset
// but we will double-check to avoid the potential of NPEs...
threadLocal = new HashMap<String, WebScriptPropertyResourceBundle>();
this.extendedBundleCache.set(threadLocal);
}
threadLocal.put(webScriptId, extensionBundle);
}
/**
* <p>A {@link ThreadLocal} reference to the file currently being processed in the model.</p>
*/
private ThreadLocal<String> fileBeingProcessed = new ThreadLocal<String>();
/**
* <p>Returns the path of the file currently being processed in the model by the current thread.
* This information is primarily provided for the purposes of generating debug information.</p>
*
* @return The path of the file currently being processed.
*/
public String getFileBeingProcessed()
{
return this.fileBeingProcessed.get();
}
/**
* <p>Sets the path of the file currently being processed in the model by the current thread.
* This information should be collected to assist with providing debug information.</p>
* @param file The path of the file currently being processed.
*/
public void setFileBeingProcessed(String file)
{
this.fileBeingProcessed.set(file);
}
/**
* <p>Retrieves an files for the evaluated modules that are extending the WebScript files being processed.</p>
*/
public List<String> getExtendingModuleFiles(String pathBeingProcessed)
{
List<String> extendingModuleFiles = new ArrayList<String>();
for (BasicExtensionModule module: this.getEvaluatedModules())
{
extendingModuleFiles.addAll(this.extensibilityModuleHandler.getExtendingModuleFiles(module, pathBeingProcessed));
}
return extendingModuleFiles;
}
/**
* <p>The list of {@link org.springframework.extensions.surf.types.ExtensionModule} instances that have been evaluated as applicable to
* this RequestContext. This is set to <code>null</code> when during instantiation and is only
* properly set the first time the <code>getEvaluatedModules</code> method is invoked. This ensures
* that module evaluation only occurs once per request.</p>
*/
private ThreadLocal<List<BasicExtensionModule>> evaluatedModules = new ThreadLocal<List<BasicExtensionModule>>();
/**
* <p>Retrieve the list of {@link org.springframework.extensions.surf.types.ExtensionModule} instances that have been evaluated as applicable
* for the current request. If this list has not yet been populated then use the {@link org.springframework.extensions.surf.extensibility.ExtensibilityModuleHandler}
* configured in the Spring application context to evaluate them.</p>
*
* @return A list of {@link org.springframework.extensions.surf.types.ExtensionModule} instances that are applicable to the current request.
*/
public List<BasicExtensionModule> getEvaluatedModules()
{
List<BasicExtensionModule> evaluatedModules = this.evaluatedModules.get();
if (evaluatedModules == null)
{
if (this.extensibilityModuleHandler == null)
{
if (logger.isErrorEnabled())
{
logger.error("No 'extensibilityModuleHandler' has been configured for this request context. Extensions cannot be processed");
}
evaluatedModules = new ArrayList<BasicExtensionModule>();
this.evaluatedModules.set(evaluatedModules);
}
else
{
evaluatedModules = this.extensibilityModuleHandler.getExtensionModules();
this.evaluatedModules.set(evaluatedModules);
}
}
return evaluatedModules;
}
/**
* <p>This is a local {@link ConfigImpl} instance that will only be used when extension modules are employed. It will
* initially be populated with the default "static" global configuration taken from the {@link ConfigService} associated
* with this {@link org.springframework.extensions.surf.RequestContext} but then updated to include global configuration provided by extension modules that
* have been evaluated to be applied to the current request.</p>
*/
private ThreadLocal<ConfigImpl> globalConfig = new ThreadLocal<ConfigImpl>();
/**
* <p>This map represents {@link ConfigSection} instances mapped by area. It will only be used when extension modules are
* employed. It will initially be populated with the default "static" configuration taken from the {@link ConfigService} associated
* with this {@link org.springframework.extensions.surf.RequestContext} but then updated to include configuration provided by extension modules that have been evaluated
* to be applied to the current request.</p>
*/
private ThreadLocal<Map<String, List<ConfigSection>>> sectionsByArea = new ThreadLocal<Map<String,List<ConfigSection>>>();
/**
* <p>A list of {@link ConfigSection} instances that are only applicable to the current request. It will only be used when extension modules are
* employed. It will initially be populated with the default "static" configuration taken from the {@link ConfigService} associated
* with this {@link org.springframework.extensions.surf.RequestContext} but then updated to include configuration provided by extension modules that have been evaluated
* to be applied to the current request.</p>
*/
private ThreadLocal<List<ConfigSection>> sections = new ThreadLocal<List<ConfigSection>>();
/**
* <p>Creates a new {@link ExtendedScriptConfigModel} instance using the local configuration generated for this request.
* If configuration for the request will be generated if it does not yet exist. It is likely that this method will be
* called multiple times within the context of a single request and although the configuration containers will always
* be the same a new {@link ExtendedScriptConfigModel} instance will always be created as the the supplied <code>xmlConfig</code>
* string could be different for each call (because each WebScript invoked in the request will supply different
* configuration.</p>
*/
public ScriptConfigModel getExtendedScriptConfigModel(String xmlConfig)
{
if (this.globalConfig.get() == null && this.sectionsByArea.get() == null && this.sections.get() == null)
{
this.getConfigExtensions();
}
return new ExtendedScriptConfigModel(getConfigService(), xmlConfig, this.globalConfig.get(), this.sectionsByArea.get(), this.sections.get());
}
/**
* <p>Creates a new {@link TemplateConfigModel} instance using the local configuration generated for this request.
* If configuration for the request will be generated if it does not yet exist. It is likely that this method will be
* called multiple times within the context of a single request and although the configuration containers will always
* be the same a new {@link TemplateConfigModel} instance will always be created as the the supplied <code>xmlConfig</code>
* string could be different for each call (because each WebScript invoked in the request will supply different
* configuration.</p>
*/
public TemplateConfigModel getExtendedTemplateConfigModel(String xmlConfig)
{
if (this.globalConfig.get() == null && this.sectionsByArea.get() == null && this.sections.get() == null)
{
this.getConfigExtensions();
}
return new ExtendedTemplateConfigModel(getConfigService(), xmlConfig, this.globalConfig.get(), this.sectionsByArea.get(), this.sections.get());
}
/**
* <p>Creates and populates the request specific configuration container objects (<code>globalConfig</code>, <code>sectionsByArea</code> &
* <code>sections</code> with a combination of the default static configuration (taken from files accessed by the {@link ConfigService}) and
* dynamic configuration taken from extension modules evaluated for the current request. </p>
*/
private void getConfigExtensions()
{
// Extended configuration is only possible if config service is an XMLConfigService...
//
// ...also, it's only necessary to populate the configuration containers if they have not already been populated. This test should also
// be carried out by the two methods ("getExtendedTemplateConfigModel" & "getExtendedTemplateConfigModel") to prevent duplication
// of effort... but in case other methods attempt to access it we will make these additional tests.
if (getConfigService() instanceof XMLConfigService && this.globalConfig == null && this.sectionsByArea == null && this.sections == null)
{
// Cast the config service for ease of access
XMLConfigService xmlConfigService = (XMLConfigService) getConfigService();
// Get the current configuration from the ConfigService - we don't want to permanently pollute
// the standard configuration with additions from the modules...
this.globalConfig.set(new ConfigImpl((ConfigImpl)xmlConfigService.getGlobalConfig())); // Make a copy of the current global config
// Initialise these with the config service values...
this.sectionsByArea.set(new HashMap<String, List<ConfigSection>>(xmlConfigService.getSectionsByArea()));
this.sections.set(new ArrayList<ConfigSection>(xmlConfigService.getSections()));
// Check to see if there are any modules that we need to apply...
List<BasicExtensionModule> evaluatedModules = this.getEvaluatedModules();
if (evaluatedModules != null && !evaluatedModules.isEmpty())
{
for (BasicExtensionModule currModule: evaluatedModules)
{
for (Element currentConfigElement: currModule.getConfigurations())
{
// Set up containers for our request specific configuration - this will contain data taken from the evaluated modules...
Map<String, ConfigElementReader> parsedElementReaders = new HashMap<String, ConfigElementReader>();
Map<String, Evaluator> parsedEvaluators = new HashMap<String, Evaluator>();
List<ConfigSection> parsedConfigSections = new ArrayList<ConfigSection>();
// Parse and process the parses configuration...
String currentArea = xmlConfigService.parseFragment(currentConfigElement, parsedElementReaders, parsedEvaluators, parsedConfigSections);
for (Map.Entry<String, Evaluator> entry : parsedEvaluators.entrySet())
{
// add the evaluators to the config service
parsedEvaluators.put(entry.getKey(), entry.getValue());
}
for (Map.Entry<String, ConfigElementReader> entry : parsedElementReaders.entrySet())
{
// add the element readers to the config service
parsedElementReaders.put(entry.getKey(), entry.getValue());
}
for (ConfigSection section : parsedConfigSections)
{
// Update local configuration with our updated data...
xmlConfigService.addConfigSection(section, currentArea, this.globalConfig.get(), this.sectionsByArea.get(), this.sections.get());
}
}
}
}
}
}
/**
* <p>Adds the <{@code}@markup> directive to the container which allows FreeMarker templates to be extended.</p>
*/
public void addExtensibilityDirectives(Map<String, Object> freeMarkerModel, ExtensibilityModel extModel)
{
MarkupDirective mud = new MarkupDirective("markup", extModel);
freeMarkerModel.put("markup", mud);
}
}

View File

@@ -0,0 +1,138 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletContext;
import org.alfresco.api.AlfrescoPublicApi;
import org.alfresco.service.cmr.repository.FileTypeImageSize;
/**
* Contains utility methods
*
* @author Roy Wetherall
*/
@AlfrescoPublicApi
public class FileTypeImageUtils
{
private static final String IMAGE_PREFIX16 = "/images/filetypes/";
private static final String IMAGE_PREFIX32 = "/images/filetypes32/";
private static final String IMAGE_PREFIX64 = "/images/filetypes64/";
private static final String IMAGE_POSTFIX_GIF = ".gif";
private static final String IMAGE_POSTFIX_PNG = ".png";
private static final String DEFAULT_FILE_IMAGE16 = IMAGE_PREFIX16 + "_default" + IMAGE_POSTFIX_GIF;
private static final String DEFAULT_FILE_IMAGE32 = IMAGE_PREFIX32 + "_default" + IMAGE_POSTFIX_GIF;
private static final String DEFAULT_FILE_IMAGE64 = IMAGE_PREFIX64 + "_default" + IMAGE_POSTFIX_PNG;
private static final Map<String, String> s_fileExtensionMap = new HashMap<String, String>(89, 1.0f);
/**
* Return the image path to the filetype icon for the specified file name string
*
* @param sc ServletContext
* @param name File name to build filetype icon path for
* @param small True for the small 16x16 icon or false for the large 32x32
*
* @return the image path for the specified node type or the default icon if not found
*/
public static String getFileTypeImage(ServletContext sc, String name, boolean small)
{
return getFileTypeImage(sc, name, (small ? FileTypeImageSize.Small : FileTypeImageSize.Medium));
}
/**
* Return the image path to the filetype icon for the specified file name string
*
* @param sc ServletContext
* @param name File name to build filetype icon path for
* @param size Size of the icon to return
*
* @return the image path for the specified node type or the default icon if not found
*/
public static String getFileTypeImage(ServletContext sc, String name, FileTypeImageSize size)
{
String image = null;
String defaultImage = null;
switch (size)
{
case Small:
defaultImage = DEFAULT_FILE_IMAGE16; break;
case Medium:
defaultImage = DEFAULT_FILE_IMAGE32; break;
case Large:
defaultImage = DEFAULT_FILE_IMAGE64; break;
}
int extIndex = name.lastIndexOf('.');
if (extIndex != -1 && name.length() > extIndex + 1)
{
String ext = name.substring(extIndex + 1).toLowerCase();
String key = ext + ' ' + size.toString();
// found file extension for appropriate size image
synchronized (s_fileExtensionMap)
{
image = s_fileExtensionMap.get(key);
if (image == null)
{
// not found create for first time
if (size != FileTypeImageSize.Large)
{
image = (size == FileTypeImageSize.Small ? IMAGE_PREFIX16 : IMAGE_PREFIX32) +
ext + IMAGE_POSTFIX_GIF;
}
else
{
image = IMAGE_PREFIX64 + ext + IMAGE_POSTFIX_PNG;
}
// does this image exist on the web-server?
if (sc != null && sc.getResourceAsStream(image) != null)
{
// found the image for this extension - save it for later
s_fileExtensionMap.put(key, image);
}
else if (sc == null)
{
// we have no ServerContext so return the default image but don't cache it
image = defaultImage;
}
else
{
// not found, save the default image for this extension instead
s_fileExtensionMap.put(key, defaultImage);
image = defaultImage;
}
}
}
}
return (image != null ? image : defaultImage);
}
}

View File

@@ -0,0 +1,102 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts;
import org.alfresco.repo.cache.AbstractMTAsynchronouslyRefreshedCache;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.util.PropertyCheck;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.extensions.webscripts.Registry;
/**
* Asynchronously refreshed cache for repository webscripts.
* <p/>
* This does not stop gratuitous calls to <i>refresh</i> but will ensure that, once an instance has been created,
* a version of the registry is returned even if it is slighly out of date. This can be changed so that it waits
* for reset but is probably not required.
*
* @author Derek Hulley
* @since 4.2.0
*/
public class RegistryAsynchronouslyRefreshedCache extends AbstractMTAsynchronouslyRefreshedCache<Registry> implements InitializingBean
{
private static Log logger = LogFactory.getLog(RegistryAsynchronouslyRefreshedCache.class);
private ObjectFactory<Registry> registryFactory;
private RetryingTransactionHelper retryingTransactionHelper;
/**
* @param registryFactory factory for web script registries
*/
public void setRegistryFactory(ObjectFactory<Registry> registryFactory)
{
this.registryFactory = registryFactory;
}
/**
* @param retryingTransactionHelper the retryingTransactionHelper to set
*/
public void setRetryingTransactionHelper(RetryingTransactionHelper retryingTransactionHelper)
{
this.retryingTransactionHelper = retryingTransactionHelper;
}
@Override
protected Registry buildCache(final String tenantId)
{
return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Registry>()
{
@Override
public Registry execute() throws Throwable
{
return doBuildCache(tenantId);
}
}, true, false);
}
/**
* This method is thread safe as per contract of {@link #buildCache(String)}.
*/
private Registry doBuildCache(String tenantId)
{
Registry registry = registryFactory.getObject();
registry.reset();
logger.info("Fetching web script registry for tenant " + tenantId);
return registry;
}
@Override
public void afterPropertiesSet() throws Exception
{
PropertyCheck.mandatory(this, "registryFactory", registryFactory);
PropertyCheck.mandatory(this, "retryingTransactionHelper", retryingTransactionHelper);
super.afterPropertiesSet();
}
}

View File

@@ -0,0 +1,82 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts;
import java.io.IOException;
import org.springframework.extensions.webscripts.ClassPathStore;
import freemarker.cache.TemplateLoader;
/**
* Extension of the SpringSurf ClassPathStore to ensure that the examination of
* last modified dates on classpath bound resources does not cause a performance
* degredation in REST heavy client applications.
* <p>
* In the repository, due to the possibility of Repository bound resources, all
* WebScript search path lists have the "delay" set to either zero seconds (no delay)
* or something close to that. This means that the FreeMarker template cache is
* always or often requesting the last modified date of a classpath resource - and
* the resources do not change. Note that the /extension classpath store still uses
* the original ClassPathStore. Otherwise all stores can be refreshed as usual via
* the Refresh WebScripts command.
*
* @author Kevin Roast
*/
public class RepoClassPathStore extends ClassPathStore
{
@Override
public TemplateLoader getTemplateLoader()
{
return new ClassPathTemplateLoader();
}
@Override
public long lastModified(String documentPath)
throws IOException
{
return -1L;
}
/**
* Class Path Store implementation of a Template Loader
* <p>
* Retrieves templates either from classes in the class path or classes inside of JAR files
* within the class path
* <p>
* This implementation always returns a fixed last modified date of -1.
*/
private class ClassPathTemplateLoader extends ClassPathStore.ClassPathTemplateLoader
{
/**
* @see freemarker.cache.TemplateLoader#getLastModified(java.lang.Object)
*/
public long getLastModified(Object templateSource)
{
return -1L;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,755 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2019 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts;
import java.io.File;
import java.io.IOException;
import java.net.SocketException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import javax.transaction.Status;
import javax.transaction.UserTransaction;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.error.ExceptionStackUtil;
import org.alfresco.repo.model.Repository;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.repo.transaction.TooBusyException;
import org.alfresco.repo.web.scripts.bean.LoginPost;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.TemplateService;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.descriptor.DescriptorService;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.TempFileProvider;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.extensions.webscripts.AbstractRuntimeContainer;
import org.springframework.extensions.webscripts.Authenticator;
import org.springframework.extensions.webscripts.Description;
import org.springframework.extensions.webscripts.Description.RequiredAuthentication;
import org.springframework.extensions.webscripts.Description.RequiredTransaction;
import org.springframework.extensions.webscripts.Description.RequiredTransactionParameters;
import org.springframework.extensions.webscripts.Description.TransactionCapability;
import org.springframework.extensions.webscripts.ServerModel;
import org.springframework.extensions.webscripts.WebScript;
import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.extensions.webscripts.WebScriptRequest;
import org.springframework.extensions.webscripts.WebScriptResponse;
/**
* Repository (server-tier) container for Web Scripts
*
* @author steveglover
* @author davidc
*/
public class RepositoryContainer extends AbstractRuntimeContainer
{
// Logger
protected static final Log logger = LogFactory.getLog(RepositoryContainer.class);
/** Component Dependencies */
private Repository repository;
private RepositoryImageResolver imageResolver;
private TransactionService transactionService;
private RetryingTransactionHelper fallbackTransactionHelper;
private AuthorityService authorityService;
private DescriptorService descriptorService;
private boolean encryptTempFiles = false;
private String tempDirectoryName = null;
private int memoryThreshold = 4 * 1024 * 1024; // 4mb
private long maxContentSize = (long) 4 * 1024 * 1024 * 1024; // 4gb
private TempOutputStreamFactory streamFactory = null;
private TempOutputStreamFactory responseStreamFactory = null;
private String preserveHeadersPattern = null;
private Class<?>[] notPublicExceptions = new Class<?>[] {};
private Class<?>[] publicExceptions = new Class<?>[] {};
/*
* Shame init is already used (by TenantRepositoryContainer).
*/
public void setup()
{
File tempDirectory = TempFileProvider.getTempDir(tempDirectoryName);
this.streamFactory = new TempOutputStreamFactory(tempDirectory, memoryThreshold, maxContentSize, encryptTempFiles, false);
this.responseStreamFactory = new TempOutputStreamFactory(tempDirectory, memoryThreshold, maxContentSize, encryptTempFiles, true);
}
public void setEncryptTempFiles(Boolean encryptTempFiles)
{
if(encryptTempFiles != null)
{
this.encryptTempFiles = encryptTempFiles.booleanValue();
}
}
public void setTempDirectoryName(String tempDirectoryName)
{
this.tempDirectoryName = tempDirectoryName;
}
public void setMemoryThreshold(Integer memoryThreshold)
{
if(memoryThreshold != null)
{
this.memoryThreshold = memoryThreshold.intValue();
}
}
public void setMaxContentSize(Long maxContentSize)
{
if(maxContentSize != null)
{
this.maxContentSize = maxContentSize.longValue();
}
}
public void setPreserveHeadersPattern(String preserveHeadersPattern)
{
this.preserveHeadersPattern = preserveHeadersPattern;
}
/**
* @param repository Repository
*/
public void setRepository(Repository repository)
{
this.repository = repository;
}
/**
* @param imageResolver RepositoryImageResolver
*/
public void setRepositoryImageResolver(RepositoryImageResolver imageResolver)
{
this.imageResolver = imageResolver;
}
/**
* @param transactionService TransactionService
*/
public void setTransactionService(TransactionService transactionService)
{
this.transactionService = transactionService;
}
/**
* @param fallbackTransactionHelper an unlimited transaction helper used to generate error responses
*/
public void setFallbackTransactionHelper(RetryingTransactionHelper fallbackTransactionHelper)
{
this.fallbackTransactionHelper = fallbackTransactionHelper;
}
/**
* @param descriptorService DescriptorService
*/
public void setDescriptorService(DescriptorService descriptorService)
{
this.descriptorService = descriptorService;
}
/**
* @param authorityService AuthorityService
*/
public void setAuthorityService(AuthorityService authorityService)
{
this.authorityService = authorityService;
}
/**
* Exceptions which may contain information that cannot be displayed in UI
*
* @param notPublicExceptions - {@link Class}&lt;?&gt;[] instance which contains list of not public exceptions
*/
public void setNotPublicExceptions(List<Class<?>> notPublicExceptions)
{
this.notPublicExceptions = new Class<?>[] {};
if((null != notPublicExceptions) && !notPublicExceptions.isEmpty())
{
this.notPublicExceptions = notPublicExceptions.toArray(this.notPublicExceptions);
}
}
public Class<?>[] getNotPublicExceptions()
{
return notPublicExceptions;
}
/**
* Exceptions which may contain information that need to display in UI
*
* @param publicExceptions - {@link Class}&lt;?&gt;[] instance which contains list of public exceptions
*/
public void setPublicExceptions(List<Class<?>> publicExceptions)
{
this.publicExceptions = new Class<?>[] {};
if((null != publicExceptions) && !publicExceptions.isEmpty())
{
this.publicExceptions = publicExceptions.toArray(this.publicExceptions);
}
}
public Class<?>[] getPublicExceptions()
{
return publicExceptions;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.Container#getDescription()
*/
public ServerModel getDescription()
{
return new RepositoryServerModel(descriptorService.getCurrentRepositoryDescriptor(), descriptorService.getServerDescriptor());
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.AbstractRuntimeContainer#getScriptParameters()
*/
public Map<String, Object> getScriptParameters()
{
Map<String, Object> params = new HashMap<String, Object>();
params.putAll(super.getScriptParameters());
addRepoParameters(params);
return params;
}
/*
* (non-Javadoc)
* @see org.alfresco.web.scripts.AbstractRuntimeContainer#getTemplateParameters()
*/
public Map<String, Object> getTemplateParameters()
{
// Ensure we have a transaction - we might be generating the status template after the main transaction failed
return fallbackTransactionHelper.doInTransaction(new RetryingTransactionCallback<Map<String, Object>>()
{
public Map<String, Object> execute() throws Throwable
{
Map<String, Object> params = new HashMap<String, Object>();
params.putAll(RepositoryContainer.super.getTemplateParameters());
params.put(TemplateService.KEY_IMAGE_RESOLVER, imageResolver.getImageResolver());
addRepoParameters(params);
return params;
}
}, true);
}
/**
* Add Repository specific parameters
*
* @param params Map<String, Object>
*/
private void addRepoParameters(Map<String, Object> params)
{
if (AlfrescoTransactionSupport.getTransactionId() != null &&
AuthenticationUtil.getFullAuthentication() != null)
{
NodeRef rootHome = repository.getRootHome();
if (rootHome != null)
{
params.put("roothome", rootHome);
}
NodeRef companyHome = repository.getCompanyHome();
if (companyHome != null)
{
params.put("companyhome", companyHome);
}
NodeRef person = repository.getFullyAuthenticatedPerson();
if (person != null)
{
params.put("person", person);
NodeRef userHome = repository.getUserHome(person);
if (userHome != null)
{
params.put("userhome", userHome);
}
}
}
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.RuntimeContainer#executeScript(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse, org.alfresco.web.scripts.Authenticator)
*/
public void executeScript(WebScriptRequest scriptReq, WebScriptResponse scriptRes, final Authenticator auth)
throws IOException
{
try
{
executeScriptInternal(scriptReq, scriptRes, auth);
}
catch (RuntimeException e)
{
Throwable hideCause = ExceptionStackUtil.getCause(e, notPublicExceptions);
Throwable displayCause = ExceptionStackUtil.getCause(e, publicExceptions);
if (displayCause == null && hideCause != null)
{
AlfrescoRuntimeException alf = null;
if (e instanceof AlfrescoRuntimeException)
{
alf = (AlfrescoRuntimeException) e;
}
else
{
// The message will not have a numerical identifier
alf = new AlfrescoRuntimeException("WebScript execution failed", e);
}
String num = alf.getNumericalId();
logger.error("Server error (" + num + ")", e);
throw new RuntimeException("Server error (" + num + "). Details can be found in the server logs.");
}
else
{
throw e;
}
}
}
protected void executeScriptInternal(WebScriptRequest scriptReq, WebScriptResponse scriptRes, final Authenticator auth)
throws IOException
{
final WebScript script = scriptReq.getServiceMatch().getWebScript();
final Description desc = script.getDescription();
final boolean debug = logger.isDebugEnabled();
// Escalate the webscript declared level of authentication to the container required authentication
// eg. must be guest if MT is enabled unless credentials are empty
RequiredAuthentication containerRequiredAuthentication = getRequiredAuthentication();
final RequiredAuthentication required = (desc.getRequiredAuthentication().compareTo(containerRequiredAuthentication) < 0 && !auth.emptyCredentials() ? containerRequiredAuthentication : desc.getRequiredAuthentication());
final boolean isGuest = scriptReq.isGuest();
if (required == RequiredAuthentication.none)
{
// TODO revisit - cleared here, in-lieu of WebClient clear
//AuthenticationUtil.clearCurrentSecurityContext();
transactionedExecuteAs(script, scriptReq, scriptRes);
}
else if ((required == RequiredAuthentication.user || required == RequiredAuthentication.admin) && isGuest)
{
throw new WebScriptException(HttpServletResponse.SC_UNAUTHORIZED, "Web Script " + desc.getId() + " requires user authentication; however, a guest has attempted access.");
}
else
{
try
{
AuthenticationUtil.pushAuthentication();
//
// Determine if user already authenticated
//
if (debug)
{
String currentUser = AuthenticationUtil.getFullyAuthenticatedUser();
logger.debug("Current authentication: " + (currentUser == null ? "unauthenticated" : "authenticated as " + currentUser));
logger.debug("Authentication required: " + required);
logger.debug("Guest login requested: " + isGuest);
}
//
// Apply appropriate authentication to Web Script invocation
//
RetryingTransactionCallback<Boolean> authWork = new RetryingTransactionCallback<Boolean>()
{
public Boolean execute() throws Exception
{
if (auth == null || auth.authenticate(required, isGuest))
{
// The user will now have been authenticated, based on HTTP Auth, Ticket etc
// Check that the user they authenticated as has appropriate access to the script
// Check to see if they supplied HTTP Auth or Ticket as guest, on a script that needs more
if (required == RequiredAuthentication.user || required == RequiredAuthentication.admin)
{
String authenticatedUser = AuthenticationUtil.getFullyAuthenticatedUser();
String runAsUser = AuthenticationUtil.getRunAsUser();
if ( (authenticatedUser == null) ||
(authenticatedUser.equals(runAsUser) && authorityService.hasGuestAuthority()) ||
(!authenticatedUser.equals(runAsUser) && authorityService.isGuestAuthority(authenticatedUser)) )
{
throw new WebScriptException(HttpServletResponse.SC_UNAUTHORIZED, "Web Script " + desc.getId() + " requires user authentication; however, a guest has attempted access.");
}
}
// Check to see if they're admin or system on an Admin only script
if (required == RequiredAuthentication.admin && !(authorityService.hasAdminAuthority() || AuthenticationUtil.getFullyAuthenticatedUser().equals(AuthenticationUtil.getSystemUserName())))
{
throw new WebScriptException(HttpServletResponse.SC_UNAUTHORIZED, "Web Script " + desc.getId() + " requires admin authentication; however, a non-admin has attempted access.");
}
if (debug)
{
String currentUser = AuthenticationUtil.getFullyAuthenticatedUser();
logger.debug("Authentication: " + (currentUser == null ? "unauthenticated" : "authenticated as " + currentUser));
}
return true;
}
return false;
}
};
boolean readOnly = transactionService.isReadOnly();
boolean requiresNew = !readOnly && AlfrescoTransactionSupport.getTransactionReadState() == TxnReadState.TXN_READ_ONLY;
if (transactionService.getRetryingTransactionHelper().doInTransaction(authWork, readOnly, requiresNew))
{
// Execute Web Script if authentication passed
// The Web Script has its own txn management with potential runAs() user
transactionedExecuteAs(script, scriptReq, scriptRes);
}
else
{
throw new WebScriptException(HttpServletResponse.SC_UNAUTHORIZED, "Authentication failed for Web Script " + desc.getId());
}
}
finally
{
//
// Reset authentication for current thread
//
AuthenticationUtil.popAuthentication();
if (debug)
{
String currentUser = AuthenticationUtil.getFullyAuthenticatedUser();
logger.debug("Authentication reset: " + (currentUser == null ? "unauthenticated" : "authenticated as " + currentUser));
}
}
}
}
/**
* Execute script within required level of transaction
*
* @param script WebScript
* @param scriptReq WebScriptRequest
* @param scriptRes WebScriptResponse
* @throws IOException
*/
protected void transactionedExecute(final WebScript script, final WebScriptRequest scriptReq, final WebScriptResponse scriptRes)
throws IOException
{
try
{
final Description description = script.getDescription();
if (description.getRequiredTransaction() == RequiredTransaction.none)
{
script.execute(scriptReq, scriptRes);
}
else
{
final BufferedRequest bufferedReq;
final BufferedResponse bufferedRes;
RequiredTransactionParameters trxParams = description.getRequiredTransactionParameters();
if (trxParams.getCapability() == TransactionCapability.readwrite)
{
if (trxParams.getBufferSize() > 0)
{
if (logger.isDebugEnabled())
logger.debug("Creating Transactional Response for ReadWrite transaction; buffersize=" + trxParams.getBufferSize());
// create buffered request and response that allow transaction retrying
bufferedReq = new BufferedRequest(scriptReq, streamFactory);
bufferedRes = new BufferedResponse(scriptRes, trxParams.getBufferSize(), responseStreamFactory);
}
else
{
if (logger.isDebugEnabled())
logger.debug("Transactional Response bypassed for ReadWrite - buffersize=0");
bufferedReq = null;
bufferedRes = null;
}
}
else
{
bufferedReq = null;
bufferedRes = null;
}
// encapsulate script within transaction
RetryingTransactionCallback<Object> work = new RetryingTransactionCallback<Object>()
{
public Object execute() throws Exception
{
try
{
if (logger.isDebugEnabled())
logger.debug("Begin retry transaction block: " + description.getRequiredTransaction() + ","
+ description.getRequiredTransactionParameters().getCapability());
if (bufferedRes == null)
{
script.execute(scriptReq, scriptRes);
}
else
{
// Reset the request and response in case of a transaction retry
bufferedReq.reset();
// REPO-4388 don't reset specified headers
bufferedRes.reset(preserveHeadersPattern);
script.execute(bufferedReq, bufferedRes);
}
}
catch(Exception e)
{
if (logger.isDebugEnabled())
{
logger.debug("Transaction exception: " + description.getRequiredTransaction() + ": " + e.getMessage());
// Note: user transaction shouldn't be null, but just in case inside this exception handler
UserTransaction userTrx = RetryingTransactionHelper.getActiveUserTransaction();
if (userTrx != null)
{
logger.debug("Transaction status: " + userTrx.getStatus());
}
}
UserTransaction userTrx = RetryingTransactionHelper.getActiveUserTransaction();
if (userTrx != null)
{
if (userTrx.getStatus() != Status.STATUS_MARKED_ROLLBACK)
{
if (logger.isDebugEnabled())
logger.debug("Marking web script transaction for rollback");
try
{
userTrx.setRollbackOnly();
}
catch(Throwable re)
{
if (logger.isDebugEnabled())
logger.debug("Caught and ignoring exception during marking for rollback: " + re.getMessage());
}
}
}
// re-throw original exception for retry
throw e;
}
finally
{
if (logger.isDebugEnabled())
logger.debug("End retry transaction block: " + description.getRequiredTransaction() + ","
+ description.getRequiredTransactionParameters().getCapability());
}
return null;
}
};
boolean readonly = description.getRequiredTransactionParameters().getCapability() == TransactionCapability.readonly;
boolean requiresNew = description.getRequiredTransaction() == RequiredTransaction.requiresnew;
// log a warning if we detect a GET webscript being run in a readwrite transaction, GET calls should
// NOT have any side effects so this scenario as a warning sign something maybe amiss, see ALF-10179.
if (logger.isDebugEnabled() && !readonly && "GET".equalsIgnoreCase(description.getMethod()))
{
logger.debug("Webscript with URL '" + scriptReq.getURL() +
"' is a GET request but it's descriptor has declared a readwrite transaction is required");
}
try
{
RetryingTransactionHelper transactionHelper = transactionService.getRetryingTransactionHelper();
if(script instanceof LoginPost)
{
//login script requires read-write transaction because of authorization intercepter
transactionHelper.setForceWritable(true);
}
transactionHelper.doInTransaction(work, readonly, requiresNew);
}
catch (TooBusyException e)
{
// Map TooBusyException to a 503 status code
throw new WebScriptException(HttpServletResponse.SC_SERVICE_UNAVAILABLE, e.getMessage(), e);
}
finally
{
// Get rid of any temporary files
if (bufferedReq != null)
{
bufferedReq.close();
}
}
// Ensure a response is always flushed after successful execution
if (bufferedRes != null)
{
bufferedRes.writeResponse();
}
}
}
catch (IOException ioe)
{
Throwable socketException = ExceptionStackUtil.getCause(ioe, SocketException.class);
Class<?> clientAbortException = null;
try
{
clientAbortException = Class.forName("org.apache.catalina.connector.ClientAbortException");
}
catch (ClassNotFoundException e)
{
// do nothing
}
// Note: if you need to look for more exceptions in the stack, then create a static array and pass it in
if ((socketException != null && socketException.getMessage().contains("Broken pipe")) || (clientAbortException != null && ExceptionStackUtil.getCause(ioe, clientAbortException) != null))
{
if (logger.isDebugEnabled())
{
logger.warn("Client has cut off communication", ioe);
}
else
{
logger.info("Client has cut off communication");
}
}
else
{
throw ioe;
}
}
}
/**
* Execute script within required level of transaction as required effective user.
*
* @param script WebScript
* @param scriptReq WebScriptRequest
* @param scriptRes WebScriptResponse
* @throws IOException
*/
private void transactionedExecuteAs(final WebScript script, final WebScriptRequest scriptReq,
final WebScriptResponse scriptRes) throws IOException
{
String runAs = script.getDescription().getRunAs();
if (runAs == null)
{
transactionedExecute(script, scriptReq, scriptRes);
}
else
{
RunAsWork<Object> work = new RunAsWork<Object>()
{
public Object doWork() throws Exception
{
transactionedExecute(script, scriptReq, scriptRes);
return null;
}
};
AuthenticationUtil.runAs(work, runAs);
}
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.AbstractRuntimeContainer#onApplicationEvent(org.springframework.context.ApplicationEvent)
*/
@Override
public void onApplicationEvent(ApplicationEvent event)
{
if (event instanceof ContextRefreshedEvent)
{
ContextRefreshedEvent refreshEvent = (ContextRefreshedEvent)event;
ApplicationContext refreshContext = refreshEvent.getApplicationContext();
if (refreshContext != null && refreshContext.equals(applicationContext))
{
RunAsWork<Object> work = new RunAsWork<Object>()
{
public Object doWork() throws Exception
{
reset();
return null;
}
};
AuthenticationUtil.runAs(work, AuthenticationUtil.getSystemUserName());
}
}
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.AbstractRuntimeContainer#getRequiredAuthentication()
*/
@Override
public RequiredAuthentication getRequiredAuthentication()
{
if (AuthenticationUtil.isMtEnabled())
{
return RequiredAuthentication.guest; // user or guest (ie. at least guest)
}
return RequiredAuthentication.none;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.RuntimeContainer#authenticate(org.alfresco.web.scripts.Authenticator, org.alfresco.web.scripts.Description.RequiredAuthentication)
*/
@Override
public boolean authenticate(Authenticator auth, RequiredAuthentication required)
{
if (auth != null)
{
AuthenticationUtil.clearCurrentSecurityContext();
return auth.authenticate(required, false);
}
return false;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.AbstractRuntimeContainer#reset()
*/
@Override
public void reset()
{
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Object>()
{
public Object execute() throws Exception
{
internalReset();
return null;
}
}, true, false);
}
private void internalReset()
{
super.reset();
}
}

View File

@@ -0,0 +1,80 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts;
import javax.servlet.ServletContext;
import org.alfresco.service.cmr.repository.FileTypeImageSize;
import org.alfresco.service.cmr.repository.TemplateImageResolver;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.web.context.ServletContextAware;
/**
* Web Scripts Image Resolver
*
* @author davidc
*/
public class RepositoryImageResolver
implements ServletContextAware, InitializingBean
{
private ServletContext servletContext;
private TemplateImageResolver imageResolver;
/* (non-Javadoc)
* @see org.springframework.web.context.ServletContextAware#setServletContext(javax.servlet.ServletContext)
*/
public void setServletContext(ServletContext context)
{
this.servletContext = context;
}
/* (non-Javadoc)
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
@SuppressWarnings("serial")
public void afterPropertiesSet()
throws Exception
{
this.imageResolver = new TemplateImageResolver()
{
public String resolveImagePathForName(String filename, FileTypeImageSize size)
{
return FileTypeImageUtils.getFileTypeImage(servletContext, filename, size);
}
};
}
/**
* @return image resolver
*/
public TemplateImageResolver getImageResolver()
{
return this.imageResolver;
}
}

View File

@@ -0,0 +1,206 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts;
import java.io.InputStream;
import java.io.Reader;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.alfresco.repo.jscript.ValueConverter;
import org.alfresco.scripts.ScriptException;
import org.alfresco.service.cmr.repository.ScriptLocation;
import org.alfresco.service.cmr.repository.ScriptService;
import org.springframework.extensions.webscripts.MultiScriptLoader;
import org.springframework.extensions.webscripts.ScriptContent;
import org.springframework.extensions.webscripts.ScriptLoader;
import org.springframework.extensions.webscripts.ScriptProcessor;
import org.springframework.extensions.webscripts.SearchPath;
import org.springframework.extensions.webscripts.Store;
import org.springframework.extensions.webscripts.WebScriptException;
/**
* Repository (server-tier) Web Script Processor
*
* @author davidc
*/
public class RepositoryScriptProcessor implements ScriptProcessor
{
// dependencies
protected ScriptService scriptService;
protected ScriptLoader scriptLoader;
protected SearchPath searchPath;
// Javascript Converter
private final ValueConverter valueConverter = new ValueConverter();
/**
* @param scriptService ScriptService
*/
public void setScriptService(ScriptService scriptService)
{
this.scriptService = scriptService;
}
/**
* @param searchPath SearchPath
*/
public void setSearchPath(SearchPath searchPath)
{
this.searchPath = searchPath;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.ScriptProcessor#findScript(java.lang.String)
*/
public ScriptContent findScript(String path)
{
return scriptLoader.getScript(path);
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.ScriptProcessor#executeScript(java.lang.String, java.util.Map)
*/
public Object executeScript(String path, Map<String, Object> model)
throws ScriptException
{
// locate script within web script stores
ScriptContent scriptContent = findScript(path);
if (scriptContent == null)
{
throw new WebScriptException("Unable to locate script " + path);
}
// execute script
return executeScript(scriptContent, model);
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.ScriptProcessor#executeScript(org.alfresco.web.scripts.ScriptContent, java.util.Map)
*/
public Object executeScript(ScriptContent content, Map<String, Object> model)
{
return scriptService.executeScript("javascript", new RepositoryScriptLocation(content), model);
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.ScriptProcessor#unwrapValue(java.lang.Object)
*/
public Object unwrapValue(Object value)
{
return valueConverter.convertValueForJava(value);
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.ScriptProcessor#reset()
*/
public void reset()
{
init();
this.scriptService.resetScriptProcessors();
}
/**
* Register script loader from each Web Script Store with Script Processor
*/
private void init()
{
List<ScriptLoader> loaders = new ArrayList<ScriptLoader>();
for (Store apiStore : searchPath.getStores())
{
ScriptLoader loader = apiStore.getScriptLoader();
if (loader == null)
{
throw new WebScriptException("Unable to retrieve script loader for Web Script store " + apiStore.getBasePath());
}
loaders.add(loader);
}
scriptLoader = new MultiScriptLoader(loaders.toArray(new ScriptLoader[loaders.size()]));
}
/**
* Script Location Facade
*/
private static class RepositoryScriptLocation implements ScriptLocation
{
private ScriptContent content;
private RepositoryScriptLocation(ScriptContent content)
{
this.content = content;
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.repository.ScriptLocation#getInputStream()
*/
public InputStream getInputStream()
{
return content.getInputStream();
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.repository.ScriptLocation#getReader()
*/
public Reader getReader()
{
return content.getReader();
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.repository.ScriptLocation#isCachable()
*/
public boolean isCachable()
{
return content.isCachable();
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.repository.ScriptLocation#isSecure()
*/
public boolean isSecure()
{
return content.isSecure();
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.repository.ScriptLocation#getPath()
*/
public String getPath()
{
return content.getPath();
}
@Override
public String toString()
{
return content.getPathDescription();
}
}
}

View File

@@ -0,0 +1,54 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts;
import org.springframework.extensions.webscripts.ScriptProcessor;
import org.springframework.extensions.webscripts.ScriptProcessorFactory;
/**
* @author Kevin Roast
*/
public class RepositoryScriptProcessorFactory implements ScriptProcessorFactory
{
private ScriptProcessor scriptProcessor;
/**
* @param scriptProcessor the ScriptProcessor to set
*/
public void setScriptProcessor(ScriptProcessor scriptProcessor)
{
this.scriptProcessor = scriptProcessor;
}
/* (non-Javadoc)
* @see org.springframework.extensions.webscripts.ScriptProcessorFactory#newInstance()
*/
public ScriptProcessor newInstance()
{
return scriptProcessor;
}
}

View File

@@ -0,0 +1,142 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts;
import org.alfresco.service.descriptor.Descriptor;
import org.springframework.extensions.webscripts.ServerModel;
/**
* Script / Template Model representing Repository Server meta-data
*
* @author davidc
*/
public class RepositoryServerModel implements ServerModel
{
private Descriptor currentDescriptor;
private Descriptor serverDescriptor;
/**
* Construct
*
* @param currentDescriptor Descriptor
* @param serverDescriptor Descriptor
*/
/*package*/ RepositoryServerModel(Descriptor currentDescriptor, Descriptor serverDescriptor)
{
this.currentDescriptor = currentDescriptor;
this.serverDescriptor = serverDescriptor;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.ServerModel#getContainerName()
*/
public String getContainerName()
{
return "Repository";
}
/*(non-Javadoc)
* @see org.alfresco.web.scripts.ServerModel#getId()
*/
public String getId()
{
return currentDescriptor.getId();
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.ServerModel#getName()
*/
public String getName()
{
return currentDescriptor.getName();
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.ServerModel#getVersionMajor()
*/
public String getVersionMajor()
{
return currentDescriptor.getVersionMajor();
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.ServerModel#getVersionMinor()
*/
public String getVersionMinor()
{
return currentDescriptor.getVersionMinor();
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.ServerModel#getVersionRevision()
*/
public String getVersionRevision()
{
return currentDescriptor.getVersionRevision();
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.ServerModel#getVersionLabel()
*/
public String getVersionLabel()
{
return currentDescriptor.getVersionLabel();
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.ServerModel#getVersionBuild()
*/
public String getVersionBuild()
{
return currentDescriptor.getVersionBuild();
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.ServerModel#getVersion()
*/
public String getVersion()
{
return currentDescriptor.getVersion();
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.ServerModel#getEdition()
*/
public String getEdition()
{
return serverDescriptor.getEdition();
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.ServerModel#getSchema()
*/
public int getSchema()
{
return currentDescriptor.getSchema();
}
}

View File

@@ -0,0 +1,261 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.alfresco.processor.ProcessorExtension;
import org.alfresco.repo.template.FreeMarkerProcessor;
import org.alfresco.repo.template.QNameAwareObjectWrapper;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.extensions.surf.util.AbstractLifecycleBean;
import org.springframework.extensions.webscripts.SearchPath;
import org.springframework.extensions.webscripts.Store;
import org.springframework.extensions.webscripts.TemplateProcessor;
import org.springframework.extensions.webscripts.WebScriptException;
import freemarker.cache.MultiTemplateLoader;
import freemarker.cache.StrongCacheStorage;
import freemarker.cache.TemplateLoader;
import freemarker.core.TemplateClassResolver;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateExceptionHandler;
import freemarker.template.Version;
/**
* Repository (server-tier) Web Script Template Processor
*
* @author davidc
*/
public class RepositoryTemplateProcessor extends FreeMarkerProcessor
implements TemplateProcessor, ApplicationContextAware, ApplicationListener
{
private ProcessorLifecycle lifecycle = new ProcessorLifecycle();
protected SearchPath searchPath;
protected String defaultEncoding;
protected Configuration templateConfig;
protected FreeMarkerProcessor freeMarkerProcessor;
private int updateDelay = 1;
/* (non-Javadoc)
* @see org.alfresco.repo.template.FreeMarkerProcessor#setDefaultEncoding(java.lang.String)
*/
@Override
public void setDefaultEncoding(String defaultEncoding)
{
this.defaultEncoding = defaultEncoding;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.TemplateProcessor#getDefaultEncoding()
*/
public String getDefaultEncoding()
{
return this.defaultEncoding;
}
/**
* @param updateDelay the time in seconds between checks on the modified date for cached templates
*/
public void setUpdateDelay(int updateDelay)
{
this.updateDelay = updateDelay;
}
/**
* @deprecated
* @param cacheSize not used anymore
*/
@Deprecated
public void setCacheSize(int cacheSize)
{
}
/**
* @param searchPath SearchPath
*/
public void setSearchPath(SearchPath searchPath)
{
this.searchPath = searchPath;
}
/**
* Set the freemarker processor
*
* @param freeMarkerProcessor the free marker processor
*/
public void setFreeMarkerProcessor(FreeMarkerProcessor freeMarkerProcessor)
{
this.freeMarkerProcessor = freeMarkerProcessor;
}
/* (non-Javadoc)
* @see org.alfresco.repo.template.FreeMarkerProcessor#getConfig()
*/
@Override
protected Configuration getConfig()
{
return templateConfig;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.TemplateProcessor#reset()
*/
public void reset()
{
if (templateConfig != null)
{
templateConfig.clearTemplateCache();
}
initConfig();
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.TemplateProcessor#hasTemplate(java.lang.String)
*/
public boolean hasTemplate(String templatePath)
{
boolean hasTemplate = false;
try
{
Template template = templateConfig.getTemplate(templatePath);
hasTemplate = (template != null);
}
catch(FileNotFoundException e)
{
// NOTE: return false as template is not found
}
catch(IOException e)
{
throw new WebScriptException("Failed to retrieve template " + templatePath, e);
}
return hasTemplate;
}
/**
* Initialise FreeMarker Configuration
*/
protected void initConfig()
{
Configuration config = new Configuration();
// setup template cache
config.setCacheStorage(new StrongCacheStorage());
config.setTemplateUpdateDelay(updateDelay);
// setup template loaders
List<TemplateLoader> loaders = new ArrayList<TemplateLoader>();
for (Store apiStore : searchPath.getStores())
{
TemplateLoader loader = apiStore.getTemplateLoader();
if (loader == null)
{
throw new WebScriptException("Unable to retrieve template loader for Web Script store " + apiStore.getBasePath());
}
loaders.add(loader);
}
MultiTemplateLoader loader = new MultiTemplateLoader(loaders.toArray(new TemplateLoader[loaders.size()]));
config.setTemplateLoader(loader);
// use our custom object wrapper that can deal with QNameMap objects directly
config.setObjectWrapper(new QNameAwareObjectWrapper());
// rethrow any exception so we can deal with them
config.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
// turn off locale sensitive lookup - to save numerous wasted calls to nodeservice.exists()
config.setLocalizedLookup(false);
// set template encoding
if (defaultEncoding != null)
{
config.setDefaultEncoding(defaultEncoding);
}
// set output encoding
config.setOutputEncoding("UTF-8");
config.setIncompatibleImprovements(new Version(2, 3, 20));
config.setNewBuiltinClassResolver(TemplateClassResolver.SAFER_RESOLVER);
templateConfig = config;
}
/**
* Tempory fix to initialise this template processor with the freeMarker extensions expected by
* the templates.
*/
private void initProcessorExtensions()
{
for (ProcessorExtension processorExtension : this.freeMarkerProcessor.getProcessorExtensions())
{
this.registerProcessorExtension(processorExtension);
}
}
/* (non-Javadoc)
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
*/
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
lifecycle.setApplicationContext(applicationContext);
}
/* (non-Javadoc)
* @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
*/
public void onApplicationEvent(ApplicationEvent event)
{
lifecycle.onApplicationEvent(event);
}
/**
* Hooks into Spring Application Lifecycle
*/
private class ProcessorLifecycle extends AbstractLifecycleBean
{
@Override
protected void onBootstrap(ApplicationEvent event)
{
initProcessorExtensions();
}
@Override
protected void onShutdown(ApplicationEvent event)
{
}
}
}

View File

@@ -0,0 +1,54 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts;
import org.springframework.extensions.webscripts.TemplateProcessor;
import org.springframework.extensions.webscripts.TemplateProcessorFactory;
/**
* @author Kevin Roast
*/
public class RepositoryTemplateProcessorFactory implements TemplateProcessorFactory
{
private TemplateProcessor templateProcessor;
/**
* @param templateProcessor the TemplateProcessor to set
*/
public void setTemplateProcessor(TemplateProcessor templateProcessor)
{
this.templateProcessor = templateProcessor;
}
/* (non-Javadoc)
* @see org.springframework.extensions.webscripts.TemplateProcessorFactory#newInstance()
*/
public TemplateProcessor newInstance()
{
return templateProcessor;
}
}

View File

@@ -0,0 +1,383 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2019 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.IvParameterSpec;
import org.alfresco.repo.content.ContentLimitViolationException;
import org.alfresco.util.TempFileProvider;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* An output stream implementation that keeps the data in memory if is less then
* the specified <b>memoryThreshold</b> otherwise it writes it to a temp file.
* <p/>
*
* Close the stream before any call to
* {@link TempOutputStream}.getInputStream().
* <p/>
*
* If <b>deleteTempFileOnClose</b> is false then use proper try-finally patterns
* to ensure that the temp file is destroyed after it is no longer needed.
*
* <pre>
* <code>try
* {
* StreamUtils.copy(new BufferedInputStream(new FileInputStream(file)), tempOutputStream);
* tempOutputStream.close();
* }
* finally
* {
* tempOutputStream.destroy();
* }
* </code>
* </pre>
*/
public class TempOutputStream extends OutputStream
{
private static final Log logger = LogFactory.getLog(TempOutputStream.class);
private static final int DEFAULT_MEMORY_THRESHOLD = 4 * 1024 * 1024; // 4mb
private static final String ALGORITHM = "AES";
private static final String MODE = "CTR";
private static final String PADDING = "PKCS5Padding";
private static final String TRANSFORMATION = ALGORITHM + '/' + MODE + '/' + PADDING;
private static final int KEY_SIZE = 128;
public static final String TEMP_FILE_PREFIX = "tempStreamFile-";
private final File tempDir;
private final int memoryThreshold;
private final long maxContentSize;
private boolean encrypt;
private boolean deleteTempFileOnClose;
private long length = 0;
private OutputStream outputStream;
private File tempFile;
private TempByteArrayOutputStream tempStream;
private Key symKey;
private byte[] iv;
/**
* Creates a TempOutputStream.
*
* @param tempDir
* the temporary directory, i.e. <code>isDir == true</code>, that
* will be used as * parent directory for creating temp file backed
* streams
* @param memoryThreshold
* the memory threshold in B
* @param maxContentSize
* the max content size in B
* @param encrypt
* true if temp files should be encrypted
* @param deleteTempFileOnClose
* true if temp files should be deleted on output stream close
* (useful if we need to cache the content for further reads). If
* this is false then we need to make sure we call
* {@link TempOutputStream}.destroy to clean up properly.
*/
public TempOutputStream(File tempDir, int memoryThreshold, long maxContentSize, boolean encrypt, boolean deleteTempFileOnClose)
{
this.tempDir = tempDir;
this.memoryThreshold = (memoryThreshold < 0) ? DEFAULT_MEMORY_THRESHOLD : memoryThreshold;
this.maxContentSize = maxContentSize;
this.encrypt = encrypt;
this.deleteTempFileOnClose = deleteTempFileOnClose;
this.tempStream = new TempByteArrayOutputStream();
this.outputStream = this.tempStream;
}
/**
* Returns the data as an InputStream
*/
public InputStream getInputStream() throws IOException
{
if (tempFile != null)
{
if (encrypt)
{
final Cipher cipher;
try
{
cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.DECRYPT_MODE, symKey, new IvParameterSpec(iv));
}
catch (Exception e)
{
destroy();
if (logger.isErrorEnabled())
{
logger.error("Cannot initialize decryption cipher", e);
}
throw new IOException("Cannot initialize decryption cipher", e);
}
return new BufferedInputStream(new CipherInputStream(new FileInputStream(tempFile), cipher));
}
return new BufferedInputStream(new FileInputStream(tempFile));
}
else
{
return new ByteArrayInputStream(tempStream.getBuffer(), 0, tempStream.getCount());
}
}
@Override
public void write(int b) throws IOException
{
update(1);
outputStream.write(b);
}
@Override
public void write(byte[] b, int off, int len) throws IOException
{
update(len);
outputStream.write(b, off, len);
}
@Override
public void flush() throws IOException
{
outputStream.flush();
}
@Override
public void close() throws IOException
{
close(deleteTempFileOnClose);
}
/**
* Closes the stream and removes the backing file (if present).
* <p/>
*
* If <b>deleteTempFileOnClose</b> is false then use proper try-finally patterns
* to ensure that the temp file is destroyed after it is no longer needed.
*
* <pre>
* <code>try
* {
* StreamUtils.copy(new BufferedInputStream(new FileInputStream(file)), tempOutputStream);
* tempOutputStream.close();
* }
* finally
* {
* tempOutputStream.destroy();
* }
* </code>
* </pre>
*/
public void destroy() throws IOException
{
close(true);
}
public long getLength()
{
return length;
}
private void closeOutputStream()
{
if (outputStream != null)
{
try
{
outputStream.flush();
}
catch (IOException e)
{
if (logger.isDebugEnabled())
{
logger.debug("Flushing the output stream failed", e);
}
}
try
{
outputStream.close();
}
catch (IOException e)
{
if (logger.isDebugEnabled())
{
logger.debug("Closing the output stream failed", e);
}
}
}
}
private void deleteTempFile()
{
if (tempFile != null)
{
try
{
boolean isDeleted = tempFile.delete();
if (!isDeleted)
{
if (logger.isDebugEnabled())
{
logger.debug("Temp file could not be deleted: " + tempFile.getAbsolutePath());
}
}
else
{
if (logger.isDebugEnabled())
{
logger.debug("Deleted temp file: " + tempFile.getAbsolutePath());
}
}
}
finally
{
tempFile = null;
}
}
}
private void close(boolean deleteTempFileOnClose)
{
closeOutputStream();
if (deleteTempFileOnClose)
{
deleteTempFile();
}
}
private BufferedOutputStream createOutputStream(File file) throws IOException
{
BufferedOutputStream fileOutputStream;
if (encrypt)
{
try
{
// Generate a symmetric key
final KeyGenerator keyGen = KeyGenerator.getInstance(ALGORITHM);
keyGen.init(KEY_SIZE);
symKey = keyGen.generateKey();
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, symKey);
iv = cipher.getIV();
fileOutputStream = new BufferedOutputStream(new CipherOutputStream(new FileOutputStream(file), cipher));
}
catch (Exception e)
{
if (logger.isErrorEnabled())
{
logger.error("Cannot initialize encryption cipher", e);
}
throw new IOException("Cannot initialize encryption cipher", e);
}
}
else
{
fileOutputStream = new BufferedOutputStream(new FileOutputStream(file));
}
return fileOutputStream;
}
private void update(int len) throws IOException
{
if (maxContentSize > -1 && length + len > maxContentSize)
{
destroy();
throw new ContentLimitViolationException("Content size violation, limit = " + maxContentSize);
}
if (tempFile == null && (tempStream.getCount() + len) > memoryThreshold)
{
File file = TempFileProvider.createTempFile(TEMP_FILE_PREFIX, ".bin", tempDir);
BufferedOutputStream fileOutputStream = createOutputStream(file);
fileOutputStream.write(this.tempStream.getBuffer(), 0, this.tempStream.getCount());
fileOutputStream.flush();
try
{
tempStream.close();
}
catch (IOException e)
{
// Ignore exception
}
tempStream = null;
tempFile = file;
outputStream = fileOutputStream;
}
length += len;
}
private static class TempByteArrayOutputStream extends ByteArrayOutputStream
{
/**
* @return The internal buffer where data is stored
*/
public byte[] getBuffer()
{
return buf;
}
/**
* @return The number of valid bytes in the buffer.
*/
public int getCount()
{
return count;
}
}
}

View File

@@ -0,0 +1,105 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2019 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts;
import java.io.File;
/**
* Factory for {@link TempOutputStream}
*/
public class TempOutputStreamFactory
{
/**
* A temporary directory, i.e. <code>isDir == true</code>, that will be used as
* parent directory for creating temp file backed streams.
*/
private final File tempDir;
private int memoryThreshold;
private long maxContentSize;
private boolean encrypt;
private boolean deleteTempFileOnClose;
/**
* Creates a {@link TempOutputStream} factory.
*
* @param tempDir
* the temporary directory, i.e. <code>isDir == true</code>, that
* will be used as * parent directory for creating temp file backed
* streams
* @param memoryThreshold
* the memory threshold in B
* @param maxContentSize
* the max content size in B
* @param encrypt
* true if temp files should be encrypted
* @param deleteTempFileOnClose
* true if temp files should be deleted on output stream close
* (useful if we need to cache the content for further reads). If
* this is false then we need to make sure we call
* {@link TempOutputStream}.destroy to clean up properly.
*/
public TempOutputStreamFactory(File tempDir, int memoryThreshold, long maxContentSize, boolean encrypt, boolean deleteTempFileOnClose)
{
this.tempDir = tempDir;
this.memoryThreshold = memoryThreshold;
this.maxContentSize = maxContentSize;
this.encrypt = encrypt;
this.deleteTempFileOnClose = deleteTempFileOnClose;
}
/**
* Creates a new {@link TempOutputStream} object
*/
public TempOutputStream createOutputStream()
{
return new TempOutputStream(tempDir, memoryThreshold, maxContentSize, encrypt, deleteTempFileOnClose);
}
public File getTempDir()
{
return tempDir;
}
public int getMemoryThreshold()
{
return memoryThreshold;
}
public long getMaxContentSize()
{
return maxContentSize;
}
public boolean isEncrypt()
{
return encrypt;
}
public boolean isDeleteTempFileOnClose()
{
return deleteTempFileOnClose;
}
}

View File

@@ -0,0 +1,130 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts;
import org.alfresco.repo.cache.AsynchronouslyRefreshedCache;
import org.alfresco.repo.tenant.TenantAdminService;
import org.alfresco.repo.tenant.TenantDeployer;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.transaction.TransactionService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.webscripts.Registry;
/**
* Tenant-aware Repository (server-tier) container for Web Scripts
*
* @author davidc
*/
public class TenantRepositoryContainer extends RepositoryContainer implements TenantDeployer
{
// Logger
protected static final Log logger = LogFactory.getLog(TenantRepositoryContainer.class);
/* Component Dependencies */
protected TenantAdminService tenantAdminService;
protected TransactionService transactionService;
private AsynchronouslyRefreshedCache<Registry> registryCache;
/**
* @param registryCache asynchronously maintained cache for script registries
*/
public void setWebScriptsRegistryCache(AsynchronouslyRefreshedCache<Registry> registryCache)
{
this.registryCache = registryCache;
}
/**
* @param tenantAdminService service to sort out tenant context
*/
public void setTenantAdminService(TenantAdminService tenantAdminService)
{
this.tenantAdminService = tenantAdminService;
}
/**
* @param transactionService service to give transactions when reading from the container
*/
public void setTransactionService(TransactionService transactionService)
{
super.setTransactionService(transactionService);
this.transactionService = transactionService;
}
@Override
public Registry getRegistry()
{
Registry registry = registryCache.get();
boolean isUpToDate = registryCache.isUpToDate();
if (!isUpToDate && logger.isDebugEnabled())
{
logger.debug("Retrieved out of date web script registry for tenant " + tenantAdminService.getCurrentUserDomain());
}
return registry;
}
@Override
public void onEnableTenant()
{
init();
}
@Override
public void onDisableTenant()
{
destroy();
}
@Override
public void init()
{
tenantAdminService.register(this);
registryCache.refresh();
super.reset();
}
@Override
public void destroy()
{
registryCache.refresh();
}
@Override
public void reset()
{
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Object>()
{
public Object execute() throws Exception
{
destroy();
init();
return null;
}
}, true, false);
}
}

View File

@@ -0,0 +1,110 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.surf.util.I18NUtil;
import org.springframework.extensions.webscripts.servlet.WebScriptServlet;
import org.springframework.extensions.webscripts.servlet.WebScriptServletRuntime;
/**
* Entry point for web scripts which can accept a tenant id in their servlet path
*
* @author davidc
*/
public class TenantWebScriptServlet extends WebScriptServlet
{
// public static final String SYSTEM_TENANT = "-system-";
// public static final String DEFAULT_TENANT = "-default-";
private static final long serialVersionUID = 2954663814419046489L;
// Logger
private static final Log logger = LogFactory.getLog(TenantWebScriptServlet.class);
protected WebScriptServletRuntime getRuntime(HttpServletRequest req, HttpServletResponse res)
{
WebScriptServletRuntime runtime = new TenantWebScriptServletRuntime(container, authenticatorFactory, req, res, serverProperties);
return runtime;
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException
{
if (logger.isDebugEnabled())
logger.debug("Processing tenant request (" + req.getMethod() + ") " + req.getRequestURL() + (req.getQueryString() != null ? "?" + req.getQueryString() : ""));
if (req.getCharacterEncoding() == null)
{
req.setCharacterEncoding("UTF-8");
}
setLanguageFromRequestHeader(req);
try
{
WebScriptServletRuntime runtime = getRuntime(req, res);
runtime.executeScript();
}
catch (IllegalStateException e)
{
if(e.getMessage().contains("getOutputStream() has already been called for this response"))
{
if(logger.isDebugEnabled())
{
logger.warn("Client has cut off communication", e);
}
else
{
logger.warn("Client has cut off communication");
}
}
else
{
throw e;
}
}
finally
{
// clear threadlocal
I18NUtil.setLocale(null);
// clear authentication and tenant context
AuthenticationUtil.clearCurrentSecurityContext();
}
}
}

View File

@@ -0,0 +1,117 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts;
import javax.servlet.http.HttpServletRequest;
import org.springframework.extensions.config.ServerProperties;
import org.springframework.extensions.surf.util.URLDecoder;
import org.springframework.extensions.webscripts.Match;
import org.springframework.extensions.webscripts.Runtime;
import org.springframework.extensions.webscripts.servlet.WebScriptServletRequest;
/**
* Web Script Request which can handle a tenant id in their servlet path
*
* @author davidc
*/
public class TenantWebScriptServletRequest extends WebScriptServletRequest
{
protected String tenant;
protected String pathInfo;
protected void parse()
{
String realPathInfo = getRealPathInfo();
// remove tenant
int idx = realPathInfo.indexOf('/', 1);
tenant = realPathInfo.substring(1, idx == -1 ? realPathInfo.length() : idx);
pathInfo = realPathInfo.substring(tenant.length() + 1);
}
/**
* Construction
*
* @param container Runtime
* @param req HttpServletRequest
* @param serviceMatch Match
* @param serverProperties ServerProperties
*/
public TenantWebScriptServletRequest(Runtime container, HttpServletRequest req, Match serviceMatch, ServerProperties serverProperties)
{
super(container, req, serviceMatch, serverProperties);
parse();
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.WebScriptRequest#getServiceContextPath()
*/
public String getServiceContextPath()
{
return getHttpServletRequest().getContextPath() + getHttpServletRequest().getServletPath() + "/" + tenant;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.WebScriptRequest#getPathInfo()
*/
public String getPathInfo()
{
return pathInfo;
}
public String getTenant()
{
return tenant;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.WebScriptRequest#getPathInfo()
*/
protected String getRealPathInfo()
{
// NOTE: Don't use req.getPathInfo() - it truncates the path at first semi-colon in Tomcat
final String requestURI = getHttpServletRequest().getRequestURI();
final String serviceContextPath = getHttpServletRequest().getContextPath() + getHttpServletRequest().getServletPath();
String pathInfo;
if (serviceContextPath.length() > requestURI.length())
{
// NOTE: assume a redirect has taken place e.g. tomcat welcome-page
// NOTE: this is unlikely, and we'll take the hit if the path contains a semi-colon
pathInfo = getHttpServletRequest().getPathInfo();
}
else
{
pathInfo = URLDecoder.decode(requestURI.substring(serviceContextPath.length()));
}
return pathInfo;
}
}

View File

@@ -0,0 +1,108 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.extensions.config.ServerProperties;
import org.springframework.extensions.surf.util.URLDecoder;
import org.springframework.extensions.webscripts.Match;
import org.springframework.extensions.webscripts.RuntimeContainer;
import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.extensions.webscripts.WebScriptRequest;
import org.springframework.extensions.webscripts.servlet.ServletAuthenticatorFactory;
import org.springframework.extensions.webscripts.servlet.WebScriptServletRuntime;
/**
* HTTP Servlet Web Script Runtime which can handle a tenant id in a web script path
*
* @author davidc
*/
public class TenantWebScriptServletRuntime extends WebScriptServletRuntime
{
public TenantWebScriptServletRuntime(RuntimeContainer container, ServletAuthenticatorFactory authFactory, HttpServletRequest req, HttpServletResponse res, ServerProperties serverProperties)
{
super(container, authFactory, req, res, serverProperties);
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.WebScriptRuntime#getScriptUrl()
*/
@Override
protected String getScriptUrl()
{
// NOTE: Don't use req.getPathInfo() - it truncates the path at first semi-colon in Tomcat
final String requestURI = req.getRequestURI();
final String serviceContextPath = req.getContextPath() + req.getServletPath();
String pathInfo;
if (serviceContextPath.length() > requestURI.length())
{
// NOTE: assume a redirect has taken place e.g. tomcat welcome-page
// NOTE: this is unlikely, and we'll take the hit if the path contains a semi-colon
pathInfo = req.getPathInfo();
}
else
{
pathInfo = URLDecoder.decode(requestURI.substring(serviceContextPath.length()));
}
// ensure tenant is specified at beginning of path
// NOTE: must contain at least root / and single character for tenant name
if (pathInfo.length() < 2)
{
throw new WebScriptException("Missing tenant name in path: " + pathInfo);
}
// remove tenant
int idx = pathInfo.indexOf('/', 1);
pathInfo = pathInfo.substring(idx == -1 ? pathInfo.length() : idx);
return pathInfo;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.WebScriptRuntime#createRequest(org.alfresco.web.scripts.WebScriptMatch)
*/
@Override
protected WebScriptRequest createRequest(Match match)
{
// TODO: construct org.springframework.extensions.webscripts.servlet.WebScriptServletResponse when
// org.alfresco.web.scripts.WebScriptServletResponse (deprecated) is removed
servletReq = new TenantWebScriptServletRequest(this, req, match, serverProperties);
return servletReq;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.WebScriptContainer#getName()
*/
public String getName()
{
return "TenantServletRuntime";
}
}

View File

@@ -0,0 +1,184 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import org.alfresco.repo.nodelocator.CompanyHomeNodeLocator;
import org.alfresco.repo.nodelocator.NodeLocatorService;
import org.alfresco.repo.nodelocator.SharedHomeNodeLocator;
import org.alfresco.repo.nodelocator.SitesHomeNodeLocator;
import org.alfresco.repo.nodelocator.UserHomeNodeLocator;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.util.ISO8601DateFormat;
import org.json.JSONObject;
import org.springframework.extensions.surf.util.Content;
import org.springframework.extensions.webscripts.WebScriptRequest;
/**
* @author Nick Smith
* @since 4.0
*
*/
public class WebScriptUtil
{
// General Keys
public static final String DATA_KEY = "data";
// NodeRef Keys
public static final String STORE_PROTOCOL = "store_protocol";
public static final String STORE_ID = "store_id";
public static final String NODE_ID = "node_id";
//Date/Calendar Keys
public static final String DATE_TIME= "dateTime";
public static final String FORMAT= "format";
public static final String TIME_ZONE= "timeZone";
public static final String ISO8601 = "ISO8601";
public static String getContent(WebScriptRequest request) throws IOException
{
Content content = request.getContent();
return content.getContent();
}
public static Map<String, Object> buildCalendarModel(Calendar calendar)
{
Map<String, Object> model = buildDateModel(calendar.getTime());
model.put(TIME_ZONE, calendar.getTimeZone().getID());
return model;
}
public static Map<String, Object> buildDateModel(Date dateTime)
{
String dateStr = ISO8601DateFormat.format(dateTime);
Map<String, Object> model = new HashMap<String, Object>();
model.put(DATE_TIME, dateStr);
model.put(FORMAT, ISO8601);
return model;
}
public static Calendar getCalendar(JSONObject json) throws ParseException
{
Date date = getDate(json);
if(date == null)
{
return null;
}
Calendar calendar = Calendar.getInstance();
String timeZone = json.optString(TIME_ZONE);
if(timeZone != null)
{
TimeZone zone = TimeZone.getTimeZone(timeZone);
calendar.setTimeZone(zone);
}
calendar.setTime(date);
return calendar;
}
public static Date getDate(JSONObject json) throws ParseException
{
if(json == null)
{
return null;
}
String dateTime = json.optString(DATE_TIME);
if(dateTime == null)
{
return null;
}
String format = json.optString(FORMAT);
if(format!= null && ISO8601.equals(format) == false)
{
SimpleDateFormat dateFormat = new SimpleDateFormat(format);
return dateFormat.parse(dateTime);
}
return ISO8601DateFormat.parse(dateTime);
}
public static Map<String, Object> createBaseModel(Map<String, Object> result)
{
Map<String, Object> model = new HashMap<String, Object>();
model.put(DATA_KEY, result);
return model;
}
public static Map<String, Object> createBaseModel(List<Map<String, Object>> results)
{
Map<String, Object> model = new HashMap<String, Object>();
model.put(DATA_KEY, results);
return model;
}
public static NodeRef getNodeRef(Map<String, String> params)
{
String protocol = params.get(STORE_PROTOCOL);
String storeId= params.get(STORE_ID);
String nodeId= params.get(NODE_ID);
if(protocol == null || storeId == null || nodeId==null )
{
return null;
}
return new NodeRef(protocol, storeId, nodeId);
}
public static NodeRef resolveNodeReference(String reference, NodeLocatorService nodeLocatorService)
{
NodeRef nodeRef = null;
switch (reference)
{
case "alfresco://company/home":
nodeRef = nodeLocatorService.getNode(CompanyHomeNodeLocator.NAME, null, null);
break;
case "alfresco://user/home":
nodeRef = nodeLocatorService.getNode(UserHomeNodeLocator.NAME, null, null);
break;
case "alfresco://company/shared":
nodeRef = nodeLocatorService.getNode(SharedHomeNodeLocator.NAME, null, null);
break;
case "alfresco://sites/home":
nodeRef = nodeLocatorService.getNode(SitesHomeNodeLocator.NAME, null, null);
break;
default:
nodeRef = new NodeRef(reference);
break;
}
return nodeRef;
}
}

View File

@@ -0,0 +1,160 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts.action;
import java.util.Map;
import java.util.NoSuchElementException;
import org.alfresco.repo.action.ActionImpl;
import org.alfresco.repo.action.ActionTrackingServiceImpl;
import org.alfresco.repo.action.RuntimeActionService;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ActionService;
import org.alfresco.service.cmr.action.ActionStatus;
import org.alfresco.service.cmr.action.ActionTrackingService;
import org.alfresco.service.cmr.action.ExecutionSummary;
import org.alfresco.service.cmr.repository.NodeService;
import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.DeclarativeWebScript;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptRequest;
/**
* @author Nick Burch
* @since 3.4
*/
public abstract class AbstractActionWebscript extends DeclarativeWebScript
{
protected NodeService nodeService;
protected ActionService actionService;
protected RuntimeActionService runtimeActionService;
protected ActionTrackingService actionTrackingService;
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
public void setActionService(ActionService actionService)
{
this.actionService = actionService;
}
public void setRuntimeActionService(RuntimeActionService runtimeActionService)
{
this.runtimeActionService = runtimeActionService;
}
public void setActionTrackingService(ActionTrackingService actionTrackingService)
{
this.actionTrackingService = actionTrackingService;
}
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status, Cache cache)
{
RunningActionModelBuilder modelBuilder = new RunningActionModelBuilder(
nodeService, actionService, actionTrackingService
);
return buildModel(modelBuilder, req, status, cache);
}
protected abstract Map<String, Object> buildModel(
RunningActionModelBuilder modelBuilder,
WebScriptRequest req,
Status status, Cache cache
);
/**
* Takes a running action ID, and returns an
* ExecutionSummary object for it. Note - doesn't
* check to see if the object exists in the
* cache though!
*/
public static ExecutionSummary getSummaryFromKey(String key)
{
return WrappedActionTrackingService.getSummaryFromKey(key);
}
/**
* Returns the ExecutionSummary for the given action if it
* is currently executing, or null if it isn't
*/
public static ExecutionSummary getSummaryFromAction(Action action)
{
// Is it running?
if(action.getExecutionStatus() == ActionStatus.Running) {
return WrappedActionTrackingService.buildExecutionSummary(action);
}
// Has it been given a execution id?
// (eg has already finished, but this one was run)
if( ((ActionImpl)action).getExecutionInstance() != -1 ) {
return WrappedActionTrackingService.buildExecutionSummary(action);
}
// Not running, and hasn't run, we can't help
return null;
}
/**
* Returns the running action ID for the given
* ExecutionSummary
*/
public static String getRunningId(ExecutionSummary summary)
{
return WrappedActionTrackingService.getRunningId(summary);
}
/**
* So we can get at protected methods, which we need as
* we use the same naming scheme as the cache in the
* interests of simplicity.
*/
private static class WrappedActionTrackingService extends ActionTrackingServiceImpl
{
private static String getRunningId(ExecutionSummary summary)
{
return ActionTrackingServiceImpl.generateCacheKey(summary);
}
protected static ExecutionSummary buildExecutionSummary(Action action)
{
return ActionTrackingServiceImpl.buildExecutionSummary(action);
}
private static ExecutionSummary getSummaryFromKey(String key)
{
try {
// Try to have the key turned into a summary for us
return ActionTrackingServiceImpl.buildExecutionSummary(key);
} catch(NoSuchElementException e) {
// Wrong format
return null;
}
}
}
}

View File

@@ -0,0 +1,86 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts.action;
import java.util.Map;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ExecutionSummary;
import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.extensions.webscripts.WebScriptRequest;
/**
* @author Nick Burch
* @since 3.4
*/
public abstract class AbstractExecuteActionWebscript extends AbstractActionWebscript
{
protected Map<String, Object> buildModel(
RunningActionModelBuilder modelBuilder,
WebScriptRequest req,
Status status, Cache cache)
{
try {
// Have the action to run be identified
Action action = identifyAction(req, status, cache);
if(action == null) {
throw new WebScriptException(
Status.STATUS_NOT_FOUND,
"No Runnable Action found with the supplied details"
);
}
// Ask for it to be run in the background
// It will be available to execute once the webscript finishes
actionService.executeAction(
action, null,
false, true
);
// Return the details if we can
ExecutionSummary summary = getSummaryFromAction(action);
if(summary == null) {
throw new WebScriptException(
Status.STATUS_EXPECTATION_FAILED,
"Action failed to be added to the pending queue"
);
}
return modelBuilder.buildSimpleModel(summary);
} catch(Exception e) {
// Transaction broke
throw new RuntimeException(e);
}
}
protected abstract Action identifyAction(
WebScriptRequest req,
Status status, Cache cache
);
}

View File

@@ -0,0 +1,79 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts.action;
import java.util.Map;
import org.alfresco.service.cmr.action.ExecutionDetails;
import org.alfresco.service.cmr.action.ExecutionSummary;
import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.extensions.webscripts.WebScriptRequest;
/**
* @author Nick Burch
* @since 3.4
*/
public class RunningActionDelete extends AbstractActionWebscript
{
@Override
protected Map<String, Object> buildModel(
RunningActionModelBuilder modelBuilder, WebScriptRequest req,
Status status, Cache cache) {
// Which action did they ask for?
String actionTrackingId =
req.getServiceMatch().getTemplateVars().get("action_tracking_id");
// Check it exists
ExecutionSummary action =
getSummaryFromKey(actionTrackingId);
if(action == null) {
throw new WebScriptException(
Status.STATUS_NOT_FOUND,
"No Running Action found with that tracking id"
);
}
ExecutionDetails details =
actionTrackingService.getExecutionDetails(action);
if(details == null) {
throw new WebScriptException(
Status.STATUS_NOT_FOUND,
"No Running Action found with that tracking id"
);
}
// Request the cancel
actionTrackingService.requestActionCancellation(action);
// Report it as having been cancelled
status.setCode(Status.STATUS_NO_CONTENT);
status.setMessage("Action cancellation requested");
status.setRedirect(true);
return null;
}
}

View File

@@ -0,0 +1,65 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts.action;
import java.util.Map;
import org.alfresco.service.cmr.action.ExecutionSummary;
import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.extensions.webscripts.WebScriptRequest;
/**
* @author Nick Burch
* @since 3.4
*/
public class RunningActionGet extends AbstractActionWebscript
{
@Override
protected Map<String, Object> buildModel(
RunningActionModelBuilder modelBuilder, WebScriptRequest req,
Status status, Cache cache) {
// Which action did they ask for?
String actionTrackingId =
req.getServiceMatch().getTemplateVars().get("action_tracking_id");
ExecutionSummary action =
getSummaryFromKey(actionTrackingId);
// Get the details, if we can
Map<String,Object> model = modelBuilder.buildSimpleModel(action);
if(model == null) {
throw new WebScriptException(
Status.STATUS_NOT_FOUND,
"No Running Action found with that tracking id"
);
}
return model;
}
}

View File

@@ -0,0 +1,145 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts.action;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.alfresco.service.cmr.action.ActionService;
import org.alfresco.service.cmr.action.ActionTrackingService;
import org.alfresco.service.cmr.action.ExecutionDetails;
import org.alfresco.service.cmr.action.ExecutionSummary;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.util.ISO8601DateFormat;
/**
* Builds up models for running actions
*
* @author Nick Burch
* @since 3.4
*/
public class RunningActionModelBuilder
{
protected static final String MODEL_DATA_ITEM = "runningAction";
protected static final String MODEL_DATA_LIST = "runningActions";
protected static final String ACTION_ID = "id";
protected static final String ACTION_TYPE = "type";
protected static final String ACTION_INSTANCE = "instance";
protected static final String ACTION_NODE_REF = "nodeRef";
protected static final String ACTION_STARTED_AT = "startedAt";
protected static final String ACTION_RUNNING_ON = "runningOn";
protected static final String ACTION_CANCEL_REQUESTED = "cancelRequested";
protected static final String ACTION_KEY = "key";
protected NodeService nodeService;
protected ActionService actionService;
protected ActionTrackingService actionTrackingService;
public RunningActionModelBuilder(NodeService nodeService, ActionService actionService,
ActionTrackingService actionTrackingService)
{
this.nodeService = nodeService;
this.actionService = actionService;
this.actionTrackingService = actionTrackingService;
}
/**
* Build a model containing a single running action
*/
protected Map<String,Object> buildSimpleModel(ExecutionSummary summary)
{
Map<String, Object> ram = buildModel(summary);
if(ram != null) {
Map<String, Object> model = new HashMap<String,Object>();
model.put(MODEL_DATA_ITEM, ram);
return model;
}
return null;
}
/**
* Build a model containing a list of running actions for the given
* list of Running Actions
*/
protected Map<String,Object> buildSimpleList(List<ExecutionSummary> runningActions)
{
List<Map<String,Object>> models = new ArrayList<Map<String,Object>>();
for(ExecutionSummary summary : runningActions) {
Map<String, Object> ram = buildModel(summary);
if(ram != null) {
models.add(ram);
}
}
// Finish up
Map<String, Object> model = new HashMap<String,Object>();
model.put(MODEL_DATA_LIST, models);
return model;
}
/**
* Build a model for a single action
*/
private Map<String,Object> buildModel(ExecutionSummary summary)
{
if(summary == null) {
return null;
}
// Get the details, if we can
ExecutionDetails details = actionTrackingService.getExecutionDetails(summary);
// Only record if still running - may have finished
// between getting the list and now
if(details != null) {
Map<String, Object> ram = new HashMap<String,Object>();
ram.put(ACTION_ID, summary.getActionId());
ram.put(ACTION_TYPE, summary.getActionType());
ram.put(ACTION_INSTANCE, summary.getExecutionInstance());
ram.put(ACTION_KEY, AbstractActionWebscript.getRunningId(summary));
ram.put(ACTION_NODE_REF, details.getPersistedActionRef());
ram.put(ACTION_RUNNING_ON, details.getRunningOn());
ram.put(ACTION_CANCEL_REQUESTED, details.isCancelRequested());
if(details.getStartedAt() != null) {
ram.put(ACTION_STARTED_AT, ISO8601DateFormat.format(details.getStartedAt()));
} else {
ram.put(ACTION_STARTED_AT, null);
}
return ram;
}
return null;
}
}

View File

@@ -0,0 +1,67 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts.action;
import java.util.List;
import java.util.Map;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ExecutionSummary;
import org.alfresco.service.cmr.repository.NodeRef;
import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptRequest;
/**
* @author Nick Burch
* @since 3.4
*/
public class RunningActionsGet extends AbstractActionWebscript
{
@Override
protected Map<String, Object> buildModel(
RunningActionModelBuilder modelBuilder, WebScriptRequest req,
Status status, Cache cache) {
List<ExecutionSummary> actions = null;
// Do they want all actions, or only certain ones?
String type = req.getParameter("type");
String nodeRef = req.getParameter("nodeRef");
if(type != null) {
actions = actionTrackingService.getExecutingActions(type);
} else if(nodeRef != null) {
NodeRef actionNodeRef = new NodeRef(nodeRef);
Action action = runtimeActionService.createAction(actionNodeRef);
actions = actionTrackingService.getExecutingActions(action);
} else {
actions = actionTrackingService.getAllExecutingActions();
}
// Build the model list
return modelBuilder.buildSimpleList(actions);
}
}

View File

@@ -0,0 +1,79 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts.action;
import java.io.IOException;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.repository.NodeRef;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.extensions.webscripts.WebScriptRequest;
/**
* @author Nick Burch
* @since 3.4
*/
public class RunningActionsPost extends AbstractExecuteActionWebscript
{
@Override
protected Action identifyAction(WebScriptRequest req, Status status,
Cache cache) {
// Which action did they ask for?
String nodeRef = req.getParameter("nodeRef");
if(nodeRef == null) {
try {
JSONObject json = new JSONObject(new JSONTokener(req.getContent().getContent()));
if(! json.has("nodeRef")) {
throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Could not find required 'nodeRef' parameter");
}
nodeRef = json.getString("nodeRef");
}
catch (IOException iox)
{
throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Could not read content from request.", iox);
}
catch (JSONException je)
{
throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Could not parse JSON from request.", je);
}
}
// Does it exist in the repo?
NodeRef actionNodeRef = new NodeRef(nodeRef);
if(! nodeService.exists(actionNodeRef)) {
return null;
}
// Load the specified action
Action action = runtimeActionService.createAction(actionNodeRef);
return action;
}
}

View File

@@ -0,0 +1,81 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts.action;
import java.util.List;
import java.util.Map;
import org.alfresco.repo.replication.ReplicationDefinitionImpl;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ExecutionSummary;
import org.alfresco.service.cmr.replication.ReplicationDefinition;
import org.alfresco.service.cmr.replication.ReplicationService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptRequest;
/**
* @author Nick Burch
* @since 3.4
*/
public class RunningReplicationActionsGet extends AbstractActionWebscript
{
private ReplicationService replicationService;
@Override
protected Map<String, Object> buildModel(
RunningActionModelBuilder modelBuilder, WebScriptRequest req,
Status status, Cache cache) {
List<ExecutionSummary> actions = null;
// Do they want all replication actions, or only certain ones?
String name = req.getParameter("name");
if(name != null) {
// Try to find a replication definition with this name
ReplicationDefinition rd = replicationService.loadReplicationDefinition(name);
// Look up what's running
if(rd != null) {
actions = actionTrackingService.getExecutingActions(rd);
}
} else {
// All replication actions
actions = actionTrackingService.getExecutingActions(
ReplicationDefinitionImpl.EXECUTOR_NAME
);
}
// Build the model list
return modelBuilder.buildSimpleList(actions);
}
public void setReplicationService(ReplicationService replicationService)
{
this.replicationService = replicationService;
}
}

View File

@@ -0,0 +1,82 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts.action;
import java.io.IOException;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.replication.ReplicationDefinition;
import org.alfresco.service.cmr.replication.ReplicationService;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.extensions.webscripts.WebScriptRequest;
/**
* @author Nick Burch
* @since 3.4
*/
public class RunningReplicationActionsPost extends AbstractExecuteActionWebscript
{
private ReplicationService replicationService;
@Override
protected Action identifyAction(WebScriptRequest req, Status status,
Cache cache) {
// Which action did they ask for?
String name = req.getParameter("name");
if(name == null) {
try {
JSONObject json = new JSONObject(new JSONTokener(req.getContent().getContent()));
if(! json.has("name")) {
throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Could not find required 'name' parameter");
}
name = json.getString("name");
}
catch (IOException iox)
{
throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Could not read content from request.", iox);
}
catch (JSONException je)
{
throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Could not parse JSON from request.", je);
}
}
// Load the specified replication definition
ReplicationDefinition replicationDefinition =
replicationService.loadReplicationDefinition(name);
return replicationDefinition;
}
public void setReplicationService(ReplicationService replicationService)
{
this.replicationService = replicationService;
}
}

View File

@@ -0,0 +1,111 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts.activities;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import org.alfresco.error.AlfrescoRuntimeException;
import org.springframework.extensions.webscripts.DeclarativeWebScript;
import org.springframework.extensions.webscripts.SearchPath;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Java-backed WebScript to get a Template from a Template Store
*/
public class TemplateWebScript extends DeclarativeWebScript
{
// Logger
protected static final Log logger = LogFactory.getLog(TemplateWebScript.class);
private SearchPath searchPath;
public void setSearchPath(SearchPath searchPath)
{
this.searchPath = searchPath;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse)
*/
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status)
{
Map<String, Object> model = new HashMap<String, Object>();
// process extension
String path = req.getExtensionPath(); // required
if ((path == null) || (path.length() == 0))
{
String msg = "Failed to getTemplate: missing {path}";
logger.error(msg);
throw new AlfrescoRuntimeException(msg);
}
else
{
if (path.endsWith(".ftl"))
{
try
{
InputStream is = searchPath.getDocument(path);
if (is != null)
{
BufferedReader br = null;
try
{
br = new BufferedReader(new InputStreamReader(is));
String line = null;
StringBuffer sb = new StringBuffer();
while(((line = br.readLine()) !=null))
{
sb.append(line);
}
model.put("template", sb.toString());
}
finally
{
if (br != null) { br.close(); };
}
}
}
catch (IOException ioe)
{
logger.error("Failed to getTemplate: " + ioe);
}
}
}
return model;
}
}

View File

@@ -0,0 +1,95 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts.activities;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.springframework.extensions.webscripts.DeclarativeWebScript;
import org.springframework.extensions.webscripts.SearchPath;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.Store;
import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.extensions.webscripts.WebScriptRequest;
/**
* Java-backed WebScript to get list of Activity Templates from a Template Store
*/
public class TemplatesWebScript extends DeclarativeWebScript
{
private SearchPath searchPath;
public void setSearchPath(SearchPath searchPath)
{
this.searchPath = searchPath;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse)
*/
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status)
{
String path = "/";
String templatePattern = "*.ftl";
// process extension
String p = req.getExtensionPath(); // optional
if ((p != null) && (p.length() > 0))
{
int idx = p.lastIndexOf("/");
if (idx != -1)
{
path = p.substring(0, idx);
templatePattern = p.substring(idx+1) + ".ftl";
}
}
Set<String> templatePaths = new HashSet<String>();
for (Store apiStore : searchPath.getStores())
{
try
{
for (String templatePath : apiStore.getDocumentPaths(path, false, templatePattern))
{
templatePaths.add(templatePath);
}
}
catch (IOException e)
{
throw new WebScriptException("Failed to search for templates from store " + apiStore, e);
}
}
Map<String, Object> model = new HashMap<String, Object>();
model.put("paths", templatePaths);
return model;
}
}

View File

@@ -0,0 +1,138 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts.activities.feed;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.activities.feed.FeedTaskProcessor;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.permissions.AccessDeniedException;
import org.alfresco.service.cmr.activities.ActivityService;
import org.alfresco.util.JSONtoFmModel;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONException;
import org.springframework.extensions.webscripts.DeclarativeWebScript;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptRequest;
/**
* Java-backed WebScript to retrieve Activity Site Feed
*/
public class SiteFeedRetrieverWebScript extends DeclarativeWebScript
{
private static final Log logger = LogFactory.getLog(SiteFeedRetrieverWebScript.class);
private ActivityService activityService;
public void setActivityService(ActivityService activityService)
{
this.activityService = activityService;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse)
*/
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status)
{
// retrieve requested format
String format = req.getFormat();
if (format == null || format.length() == 0)
{
format = getDescription().getDefaultFormat();
}
String extensionPath = req.getExtensionPath();
String[] extParts = extensionPath == null ? new String[1] : extensionPath.split("/");
String siteId = null;
if (extParts.length == 1)
{
siteId = extParts[0];
}
else
{
throw new AlfrescoRuntimeException("Unexpected extension: " + extensionPath);
}
// map feed collection format to feed entry format (if not the same), eg.
// atomfeed -> atomentry
// atom -> atomentry
if (format.equals("atomfeed") || format.equals("atom"))
{
format = "atomentry";
}
Map<String, Object> model = new HashMap<String, Object>();
try
{
List<String> feedEntries = activityService.getSiteFeedEntries(siteId);
if (format.equals(FeedTaskProcessor.FEED_FORMAT_JSON))
{
model.put("feedEntries", feedEntries);
model.put("siteId", siteId);
}
else
{
List<Map<String, Object>> activityFeedModels = new ArrayList<Map<String, Object>>();
try
{
for (String feedEntry : feedEntries)
{
activityFeedModels.add(JSONtoFmModel.convertJSONObjectToMap(feedEntry));
}
}
catch (JSONException je)
{
throw new AlfrescoRuntimeException("Unable to get user feed entries: " + je.getMessage());
}
model.put("feedEntries", activityFeedModels);
model.put("siteId", siteId);
}
}
catch (AccessDeniedException ade)
{
// implies that site either does not exist or is private (and current user is not admin or a member) - hence return 401 (unauthorised)
String currentUser = AuthenticationUtil.getFullyAuthenticatedUser();
status.setCode(Status.STATUS_UNAUTHORIZED);
logger.warn("Unable to get site feed entries for '" + siteId + "' (site does not exist or is private) - currently logged in as '" + currentUser +"'");
model.put("feedEntries", null);
model.put("siteId", "");
}
return model;
}
}

View File

@@ -0,0 +1,217 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts.activities.feed;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.query.PagingRequest;
import org.alfresco.repo.activities.feed.FeedTaskProcessor;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.permissions.AccessDeniedException;
import org.alfresco.service.cmr.activities.ActivityService;
import org.alfresco.service.cmr.subscriptions.PagingFollowingResults;
import org.alfresco.service.cmr.subscriptions.SubscriptionService;
import org.alfresco.util.JSONtoFmModel;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONException;
import org.springframework.extensions.webscripts.DeclarativeWebScript;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptRequest;
/**
* Java-backed WebScript to retrieve Activity User Feed
*/
public class UserFeedRetrieverWebScript extends DeclarativeWebScript
{
private static final Log logger = LogFactory.getLog(UserFeedRetrieverWebScript.class);
// URL request parameter names
public static final String PARAM_SITE_ID = "s";
public static final String PARAM_EXCLUDE_THIS_USER = "exclUser";
public static final String PARAM_EXCLUDE_OTHER_USERS = "exclOthers";
public static final String PARAM_ONLY_FOLLOWING = "following";
public static final String PARAM_ACTIVITY_FILTER = "activityFilter";
private ActivityService activityService;
private SubscriptionService subscriptionService;
private boolean userNamesAreCaseSensitive = false;
public void setActivityService(ActivityService activityService)
{
this.activityService = activityService;
}
public void setSubscriptionService(SubscriptionService subscriptionService)
{
this.subscriptionService = subscriptionService;
}
public void setUserNamesAreCaseSensitive(boolean userNamesAreCaseSensitive)
{
this.userNamesAreCaseSensitive = userNamesAreCaseSensitive;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse)
*/
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status)
{
// retrieve requested format
String format = req.getFormat();
if (format == null || format.length() == 0)
{
format = getDescription().getDefaultFormat();
}
// process extension
String extensionPath = req.getExtensionPath();
String[] extParts = extensionPath == null ? new String[1] : extensionPath.split("/");
String feedUserId = null;
if (extParts.length == 1)
{
feedUserId = extParts[0];
}
else if (extParts.length > 1)
{
throw new AlfrescoRuntimeException("Unexpected extension: " + extensionPath);
}
// process arguments
String siteId = req.getParameter(PARAM_SITE_ID); // optional
String exclThisUserStr = req.getParameter(PARAM_EXCLUDE_THIS_USER); // optional
String exclOtherUsersStr = req.getParameter(PARAM_EXCLUDE_OTHER_USERS); // optional
String onlyFollowingStr = req.getParameter(PARAM_ONLY_FOLLOWING); // optional
String activityFilterStr = req.getParameter(PARAM_ACTIVITY_FILTER); // optional
boolean exclThisUser = false;
if ((exclThisUserStr != null) && (exclThisUserStr.equalsIgnoreCase("true") || exclThisUserStr.equalsIgnoreCase("t")))
{
exclThisUser = true;
}
boolean exclOtherUsers = false;
if ((exclOtherUsersStr != null) && (exclOtherUsersStr.equalsIgnoreCase("true") || exclOtherUsersStr.equalsIgnoreCase("t")))
{
exclOtherUsers = true;
}
Set<String> userFilter = null;
if ((onlyFollowingStr != null) && (onlyFollowingStr.equalsIgnoreCase("true") || onlyFollowingStr.equalsIgnoreCase("t")))
{
userFilter = new HashSet<String>();
if (subscriptionService.isActive()) {
PagingFollowingResults following = subscriptionService.getFollowing(AuthenticationUtil.getRunAsUser(), new PagingRequest(-1, null));
if (following.getPage() != null)
{
for (String userName : following.getPage())
{
userFilter.add(this.userNamesAreCaseSensitive ? userName : userName.toLowerCase());
}
}
}
}
Set<String> activityFilter = null;
if (activityFilterStr != null)
{
activityFilter = new HashSet<String>();
String[] activities = activityFilterStr.split(",");
for (String s : activities)
{
if (s.trim().length() > 0)
{
activityFilter.add(s.trim());
}
}
if (activityFilter.size() == 0)
{
activityFilter = null;
}
}
if ((feedUserId == null) || (feedUserId.length() == 0))
{
feedUserId = AuthenticationUtil.getFullyAuthenticatedUser();
}
// map feed collection format to feed entry format (if not the same), eg.
// atomfeed -> atomentry
// atom -> atomentry
if (format.equals("atomfeed") || format.equals("atom"))
{
format = "atomentry";
}
Map<String, Object> model = new HashMap<String, Object>();
try
{
List<String> feedEntries = activityService.getUserFeedEntries(feedUserId, siteId, exclThisUser, exclOtherUsers, userFilter, activityFilter);
if (format.equals(FeedTaskProcessor.FEED_FORMAT_JSON))
{
model.put("feedEntries", feedEntries);
model.put("siteId", siteId);
}
else
{
List<Map<String, Object>> activityFeedModels = new ArrayList<Map<String, Object>>();
try
{
for (String feedEntry : feedEntries)
{
activityFeedModels.add(JSONtoFmModel.convertJSONObjectToMap(feedEntry));
}
}
catch (JSONException je)
{
throw new AlfrescoRuntimeException("Unable to get user feed entries: " + je.getMessage());
}
model.put("feedEntries", activityFeedModels);
model.put("feedUserId", feedUserId);
}
}
catch (AccessDeniedException ade)
{
status.setCode(Status.STATUS_UNAUTHORIZED);
logger.warn("Unable to get user feed entries for '" + feedUserId + "' - currently logged in as '" + AuthenticationUtil.getFullyAuthenticatedUser() +"'");
return null;
}
return model;
}
}

View File

@@ -0,0 +1,122 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts.admin;
import java.util.Collections;
import java.util.Map;
import org.alfresco.service.cmr.admin.RepoAdminService;
import org.alfresco.service.cmr.admin.RepoUsage;
import org.alfresco.service.cmr.admin.RepoUsageStatus.RepoUsageLevel;
import org.alfresco.service.descriptor.DescriptorService;
import org.alfresco.service.license.LicenseDescriptor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.surf.util.I18NUtil;
import org.springframework.extensions.webscripts.DeclarativeWebScript;
/**
* Abstract implementation for scripts that access the {@link RepoAdminService}.
*
* @author Derek Hulley
* @since 3.4
*/
public abstract class AbstractAdminWebScript extends DeclarativeWebScript
{
public static final String JSON_KEY_LAST_UPDATE = "lastUpdate";
public static final String JSON_KEY_USERS = "users";
public static final String JSON_KEY_DOCUMENTS = "documents";
public static final String JSON_KEY_LICENSE_MODE = "licenseMode";
public static final String JSON_KEY_READ_ONLY = "readOnly";
public static final String JSON_KEY_UPDATED = "updated";
public static final String JSON_KEY_LICENSE_VALID_UNTIL = "licenseValidUntil";
public static final String JSON_KEY_LICENSE_HOLDER = "licenseHolder";
public static final String JSON_KEY_LEVEL = "level";
public static final String JSON_KEY_WARNINGS = "warnings";
public static final String JSON_KEY_ERRORS = "errors";
/**
* Logger that can be used by subclasses.
*/
protected final Log logger = LogFactory.getLog(this.getClass());
protected RepoAdminService repoAdminService;
protected DescriptorService descriptorService;
/**
* @param repoAdminService the service that provides the functionality
*/
public void setRepoAdminService(RepoAdminService repoAdminService)
{
this.repoAdminService = repoAdminService;
}
/**
* @param descriptorService the service that provides the functionality
*/
public void setDescriptorService(DescriptorService descriptorService)
{
this.descriptorService = descriptorService;
}
/**
* Return an I18N'd message for the given key or the key itself if not present
*
* @param args arguments to replace the variables in the message
*/
protected String getI18NMessage(String key, Object ... args)
{
return I18NUtil.getMessage(key, args);
}
/**
* Helper to assign JSON return variables based on the repository usage data.
*/
protected void putUsageInModel(
Map<String, Object> model,
RepoUsage repoUsage,
boolean updated)
{
model.put(JSON_KEY_LAST_UPDATE, repoUsage.getLastUpdate());
model.put(JSON_KEY_USERS, repoUsage.getUsers());
model.put(JSON_KEY_DOCUMENTS, repoUsage.getDocuments());
model.put(JSON_KEY_LICENSE_MODE, repoUsage.getLicenseMode());
model.put(JSON_KEY_READ_ONLY, repoUsage.isReadOnly());
model.put(JSON_KEY_LICENSE_VALID_UNTIL, repoUsage.getLicenseExpiryDate());
model.put(JSON_KEY_UPDATED, updated);
// Add license holder
LicenseDescriptor license = descriptorService.getLicenseDescriptor();
if (license != null)
{
model.put(JSON_KEY_LICENSE_HOLDER, license.getHolderOrganisation());
}
model.put(JSON_KEY_LEVEL, RepoUsageLevel.OK.ordinal());
model.put(JSON_KEY_WARNINGS, Collections.emptyList());
model.put(JSON_KEY_ERRORS, Collections.emptyList());
}
}

View File

@@ -0,0 +1,121 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts.admin;
import java.io.PrintWriter;
import java.io.StringWriter;
import org.alfresco.repo.admin.BaseInterpreter;
import org.alfresco.repo.processor.BaseProcessorExtension;
/**
* Console Interpeter script extension - dynamically binds to the configured BaseInterpreter instance.
* This avoids the need for a specific bean class per script interpreter.
*
* @see org.alfresco.repo.admin.BaseInterpreter
* See script beans configured in 'web-scripts-application-context.xml'.
*
* @author Kevin Roast
* @since 5.1
*/
public class DynamicInterpreterExtension extends BaseProcessorExtension
{
private BaseInterpreter interpreter;
private long duration;
private String result = "";
private String command = "";
/**
* Set the BaseInterpreter to use when executing commands and retrieving the command result.
*
* @param interpreter For example, repoAdminInterpreter
*/
public void setInterpreter(BaseInterpreter interpreter)
{
this.interpreter = interpreter;
}
private BaseInterpreter getInterpreter()
{
return this.interpreter;
}
/**
* Script execute command gateway.
*
* @param command string to execute
*/
public void executeCmd(String command)
{
this.command = command;
this.interpretCommand(command);
}
/**
* @return the command duration
*/
public long getDuration()
{
return this.duration;
}
/**
* @return the command result
*/
public String getResult()
{
return this.result;
}
/**
* @return the command last executed
*/
public String getCommand()
{
return this.command;
}
/**
* Interpret console command using the configured Interpreter
*
* @param command command
*/
private void interpretCommand(String command)
{
try
{
long startms = System.currentTimeMillis();
this.result = getInterpreter().interpretCommand(command);
this.duration = System.currentTimeMillis() - startms;
}
catch (Throwable e)
{
StringWriter stackTrace = new StringWriter();
e.printStackTrace(new PrintWriter(stackTrace));
this.result = stackTrace.toString();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,59 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts.admin;
import java.util.HashMap;
import java.util.Map;
import org.alfresco.service.cmr.admin.RepoUsage;
import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptRequest;
/**
* GET the repository {@link RepoUsage restrictions}.
*
* @author Derek Hulley
* @since 3.4
*/
public class RepoRestrictionsGet extends AbstractAdminWebScript
{
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status, Cache cache)
{
Map<String, Object> model = new HashMap<String, Object>(7);
RepoUsage restrictions = repoAdminService.getRestrictions();
putUsageInModel(model, restrictions, false);
// Done
if (logger.isDebugEnabled())
{
logger.debug("Result: \n\tRequest: " + req + "\n\tModel: " + model);
}
return model;
}
}

Some files were not shown because too many files have changed in this diff Show More