├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── alfresco-ceph-rados ├── Dockerfile ├── assets │ └── alfresco-global.properties ├── docker-compose.yml ├── pom.xml └── src │ └── main │ ├── amp │ ├── config │ │ └── alfresco │ │ │ └── module │ │ │ └── alfresco-ceph │ │ │ ├── alfresco-global.properties │ │ │ ├── caching-context.xml.sample │ │ │ ├── log4j.properties │ │ │ └── module-context.xml │ └── module.properties │ └── java │ └── fr │ └── jeci │ └── alfresco │ └── ceph │ ├── CephContentReader.java │ ├── CephContentWriter.java │ ├── RadosReadableByteChannel.java │ ├── RadosServiceImpl.java │ └── RadosWritableByteChannel.java ├── alfresco-object-storage-commons ├── pom.xml └── src │ └── main │ └── java │ └── fr │ └── jeci │ └── alfresco │ ├── ByteBufWritableByteChannel.java │ ├── ObjectStorageContentStore.java │ └── ObjectStorageService.java ├── alfresco-openio ├── Dockerfile ├── assets │ └── alfresco-global.properties ├── docker-compose.yml ├── pom.xml └── src │ └── main │ ├── amp │ ├── config │ │ └── alfresco │ │ │ └── module │ │ │ └── alfresco-openio │ │ │ ├── alfresco-global.properties │ │ │ ├── caching-context.xml.sample │ │ │ ├── log4j.properties │ │ │ └── module-context.xml │ └── module.properties │ └── java │ └── fr │ └── jeci │ └── alfresco │ └── openio │ ├── OpenIOChannel.java │ ├── OpenIOContentReader.java │ ├── OpenIOContentWriter.java │ └── OpenIOServiceImpl.java ├── alfresco-swift ├── Dockerfile ├── assets │ └── alfresco-global.properties ├── pom.xml └── src │ └── main │ ├── amp │ ├── config │ │ └── alfresco │ │ │ └── module │ │ │ └── alfresco-swift │ │ │ ├── alfresco-global.properties │ │ │ ├── caching-context.xml.sample │ │ │ ├── log4j.properties │ │ │ └── module-context.xml │ └── module.properties │ └── java │ └── fr │ └── jeci │ └── alfresco │ └── swift │ ├── SwiftChannel.java │ ├── SwiftContentReader.java │ ├── SwiftContentWriter.java │ └── SwiftServiceImpl.java └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | **.idea 3 | **.classpath 4 | **.project 5 | **.ipr 6 | **.iml 7 | **.log 8 | **.log* 9 | **.settings 10 | **bin 11 | *.DS_Store 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: bash 2 | 3 | services: 4 | - docker 5 | 6 | script: 7 | - docker run --rm -v $(pwd):/root/sources -w /root/sources maven:3.3.9-jdk-8 mvn clean install -DskipTests=true -Dmaven.javadoc.skip=true -B -V 8 | 9 | after_success: 10 | - if [ "$TRAVIS_TAG" ]; then 11 | docker build -t jeci/alfresco-platform-ceph-rados:$TRAVIS_TAG -t jeci/alfresco-platform-ceph-rados:latest alfresco-ceph-rados; 12 | docker build -t jeci/alfresco-platform-openio:$TRAVIS_TAG -t jeci/alfresco-platform-openio:latest alfresco-openio; 13 | docker build -t jeci/alfresco-platform-swift:$TRAVIS_TAG -t jeci/alfresco-platform-swift:latest alfresco-swift; 14 | docker login -u="$DOCKER_USERNAME" -p="$DOCKER_PASSWORD"; 15 | docker push jeci/alfresco-platform-ceph-rados; 16 | docker push jeci/alfresco-platform-openio; 17 | docker push jeci/alfresco-platform-swift; 18 | fi 19 | 20 | deploy: 21 | provider: releases 22 | api_key: 23 | secure: GdwzvHcDmW8RZZZzG6FCRMEf/whE9ER1HukxEQNHPuVS+PCCb9hmsCgyauMP7MvL72GCJ+IB13f2x3BYRjdnG8n9yszUlgYvjYeEKCa58GmnDeHUxd+WS3ireZJhnYBSkLN920PI1WUjczye9d/9Tzma+1j2xTt+SPvmDmYueRQ3gulP1119lGJSdicitBh9xTExSwyPVLrhG1z6KHGFOQE7G5c/iiIoZXgErmzak6acp/HwErGYBAcDAOPLZsazzyyoGrnydbyyTWyQxGhOz1cJ0VPF2POnAgQ/GWGPQTBvOaDqN+XVUMTH1eZ6At6OsOI1GI2UqrN10u7WLClWP6KWetXgL6vaG9DztR3O7XO/EyfSEBua1BX4hiiCdd7nkMVWNAIkkntuDpqGSNthejaLYTS6TXWnLydD33ScVSV+XeL+2gyH5E1GT94mGleZvi0jyzglwGoAxLwN+w6ZWNEkymN5Qm+F7hGvWRv2HsqafPENnK9m/tpqJ2TC8X8gEjVIo9DspCChLphkhYTHZBVj0CitSJIUaHvZEqGkU/emorSHEhXNf1smkYpCg0/kJ2OkNYTO9pKY1e+WCrtHM4+t5Zkng3lNePx11s0Qm8bscQZSllCWe0IRMWb2FMbrYUWEC98W7CK/7AiH5PS7P6dv5h+bY2BRP38iWnSVqDk= 24 | file: 25 | - "alfresco-ceph-rados/target/*.amp" 26 | - "alfresco-openio/target/*.amp" 27 | - "alfresco-swift/target/*.amp" 28 | file_glob: true 29 | skip_cleanup: true 30 | on: 31 | repo: jeci-sarl/alfresco-object-storage-connectors 32 | tags: true 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Object Storage Connectors for Alfresco 2 | 3 | This project provides connectors to use Alfresco with Content Store based on Software Defined Storage. 4 | 5 | Currently 3 connectors for : 6 | 7 | * [Red Hat Ceph Storage](https://www.redhat.com/fr/technologies/storage/ceph) using [rados](http://docs.ceph.com/docs/master/rados/api/librados-intro/) 8 | * [OpenIO](http://openio.io/) 9 | * [Openstack Swift](http://docs.openstack.org/developer/swift/) 10 | 11 | [![Build Status](https://travis-ci.org/jeci-sarl/alfresco-object-storage-connectors.svg?branch=master)](https://travis-ci.org/jeci-sarl/alfresco-object-storage-connectors) 12 | 13 | 14 | ## Installation 15 | 16 | All three connectors are available as Alfresco modules AMP, and could be install using the [default procedure](http://docs.alfresco.com/5.2/tasks/amp-install.html). 17 | 18 | Then you have to edit `alfresco-global.properties` for supply configurations and credentials. 19 | 20 | Target properties are different for each connectors 21 | 22 | ### Ceph Rados Configuration 23 | 24 | ``` ini 25 | ceph.configFile=/etc/ceph/ceph.conf 26 | ceph.id=client.admin 27 | ceph.pool=alfresco 28 | ceph.clusterName=ceph 29 | ``` 30 | 31 | 32 | ### OpenIO Configuration 33 | 34 | ``` ini 35 | openio.target=http://127.0.0.1:6006 36 | openio.namespace=OPENIO 37 | openio.account=alfresco 38 | openio.container=alfresco 39 | ``` 40 | 41 | 42 | ### OpenStack Swift Configuration 43 | 44 | ``` ini 45 | swift.username=user:swift 46 | swift.password=abcdefghijklmnop 47 | swift.url=https://s3.example.org/auth/1.0 48 | swift.tenantId= 49 | swift.tenantName= 50 | swift.containerName=alfresco 51 | ``` 52 | 53 | 54 | ## License 55 | 56 | This project is released under the [LGPL, Version 3](https://www.gnu.org/licenses/lgpl.html). 57 | 58 | 59 | ## Reporting Issues and Community Support 60 | 61 | Report issues (and contribute!) [here](https://github.com/jeci-sarl/alfresco-object-storage-connectors/issues?milestone=1&state=open). 62 | 63 | ## Engineering support 64 | 65 | [Jeci SARL](https://jeci.fr/about.html) offers annually contracted Level 3 support. 66 | 67 | - Diagnose and correcting bugs 68 | - Port / adapt code to any Alfresco version (Community or Enterprise) 69 | - Port / adapt code to any SDS version 70 | 71 | ## Authors 72 | 73 | - Jérémie Lesage - [Jeci](https://jeci.fr) 74 | - Florent Manens - [Beezim](https://beezim.fr) 75 | 76 | 77 | ## Alternatives 78 | 79 | * https://github.com/rmberg/alfresco-s3-adapter 80 | * https://github.com/douglascrp/alfresco-cloud-store 81 | * https://github.com/EisenVault/ev-alfresco-azure-adapter 82 | -------------------------------------------------------------------------------- /alfresco-ceph-rados/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM jeci/alfresco-platform:5.2.f 2 | MAINTAINER Jeremie Lesage 3 | 4 | 5 | ENV ceph_stable_release=jewel 6 | 7 | RUN apt-get update \ 8 | && apt-get install -y --no-install-recommends apt-transport-https \ 9 | && wget -q -O- 'https://download.ceph.com/keys/release.asc' | apt-key add - \ 10 | && echo deb https://download.ceph.com/debian-${ceph_stable_release}/ jessie main | tee /etc/apt/sources.list.d/ceph.list \ 11 | && apt-get update \ 12 | && apt-get install -y --no-install-recommends \ 13 | libcephfs-java \ 14 | librados2 \ 15 | libjna-java \ 16 | && rm -r /var/lib/apt/lists/* 17 | 18 | COPY target/alfresco-ceph-*.amp /root/amp/ 19 | 20 | RUN java -jar /root/alfresco-mmt.jar install /root/amp/ /usr/local/tomcat/webapps/alfresco -nobackup -directory 21 | 22 | COPY assets/alfresco-global.properties /usr/local/tomcat/shared/classes/alfresco-global.properties 23 | -------------------------------------------------------------------------------- /alfresco-ceph-rados/assets/alfresco-global.properties: -------------------------------------------------------------------------------- 1 | ceph.configFile=/etc/ceph/ceph.conf 2 | ceph.id=client.admin 3 | ceph.pool=alfresco 4 | ceph.clusterName=ceph 5 | -------------------------------------------------------------------------------- /alfresco-ceph-rados/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | # CONFIGURATION POUR VPS SSD 3 de OVH 3 | # 2vCores, 8Go RAM, 40Go SSD 4 | volumes: 5 | alf_logs: 6 | alf_data: 7 | share_logs: 8 | solr_logs: 9 | solr_data: 10 | pgsql_data: 11 | ceph-etc: 12 | 13 | 14 | networks: 15 | alf-share: 16 | internal: 17 | driver: bridge 18 | ipam: 19 | driver: default 20 | config: 21 | - subnet: 192.168.165.0/24 22 | gateway: 192.168.165.1 23 | 24 | services: 25 | alfresco: 26 | image: jeci/alfresco-platform-ceph-rados 27 | environment: 28 | CATALINA_OPTS: "-Xms512m -Xmx1G -XX:+UseConcMarkSweepGC " 29 | depends_on: 30 | - postgresql 31 | - libreoffice 32 | - ceph 33 | ulimits: 34 | nproc: 65535 35 | nofile: 36 | soft: 20000 37 | hard: 40000 38 | networks: 39 | - alf-share 40 | - internal 41 | ports: 42 | - "8081:8080" 43 | volumes: 44 | - "alf_logs:/usr/local/tomcat/logs/" 45 | - "alf_data:/opt/alf_data" 46 | - "ceph-etc:/etc/ceph" 47 | tmpfs: 48 | - /tmp 49 | - /usr/local/tomcat/temp/:exec 50 | - /usr/local/tomcat/work/ 51 | 52 | 53 | share: 54 | image: jeci/alfresco-share:5.2.e 55 | restart: always 56 | environment: 57 | CATALINA_OPTS: "-Xms512m -Xmx1G -XX:+UseConcMarkSweepGC " 58 | depends_on: 59 | - alfresco 60 | networks: 61 | - alf-share 62 | ports: 63 | - "8080:8080" 64 | volumes: 65 | - "share_logs:/usr/local/tomcat/logs/" 66 | tmpfs: 67 | - /tmp 68 | - /usr/local/tomcat/temp/ 69 | - /usr/local/tomcat/work/ 70 | 71 | solr: 72 | image: jeci/alfresco-solr:5.2.f 73 | environment: 74 | CATALINA_OPTS: "-Xms512m -Xmx1G -XX:+UseG1GC -XX:+ParallelRefProcEnabled -XX:G1HeapRegionSize=8m -XX:MaxGCPauseMillis=200 " 75 | depends_on: 76 | - alfresco 77 | ulimits: 78 | nproc: 65535 79 | nofile: 80 | soft: 20000 81 | hard: 40000 82 | networks: 83 | - internal 84 | volumes: 85 | - "solr_logs:/usr/local/tomcat/logs/" 86 | - "solr_data:/opt/solr_data" 87 | tmpfs: 88 | - /tmp 89 | - /usr/local/tomcat/temp/ 90 | - /usr/local/tomcat/work/ 91 | 92 | postgresql: 93 | image: postgres:9.4 94 | environment: 95 | - POSTGRES_DB=alfresco 96 | - POSTGRES_PASSWORD=alfresco 97 | - POSTGRES_USER=alfresco 98 | networks: 99 | - internal 100 | volumes: 101 | - "pgsql_data:/var/lib/postgresql/data" 102 | 103 | libreoffice: 104 | image: jeci/alfresco-libreoffice:5.2.7 105 | restart: always 106 | user: root 107 | networks: 108 | - internal 109 | 110 | ceph: 111 | image: ceph/demo 112 | container_name: ceph-service 113 | environment: 114 | MON_IP: 192.168.165.10 115 | CEPH_PUBLIC_NETWORK: 192.168.165.0/24 116 | volumes: 117 | - "ceph-etc:/etc/ceph" 118 | networks: 119 | internal: 120 | ipv4_address: 192.168.165.10 121 | stdin_open: true 122 | tty: true 123 | 124 | ceph-client: 125 | image: ceph/rados 126 | container_name: ceph-client 127 | volumes: 128 | - "ceph-etc:/etc/ceph" 129 | - "./output:/output" 130 | depends_on: 131 | - ceph 132 | networks: 133 | - internal 134 | # command: "mkpool alfresco" 135 | command: "lspools" 136 | -------------------------------------------------------------------------------- /alfresco-ceph-rados/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | alfresco-ceph-rados 6 | 1.0 7 | Rados Ceph Connector for Alfresco 8 | amp 9 | Rados Ceph (aka Red Hat Ceph Storage) module connector for Alfresco 10 | 11 | 12 | fr.jeci.alfresco-object-storage 13 | alfresco-object-storage-parent 14 | 1.0.0 15 | 16 | 17 | 18 | 19 | GNU Lesser General Public License v3.0 or later 20 | http://www.gnu.org/licenses/lgpl-3.0-standalone.html 21 | 22 | 23 | 24 | 25 | 26 | fr.jeci.alfresco-object-storage 27 | alfresco-object-storage-commons 28 | 1.0.0 29 | 30 | 31 | 32 | ${alfresco.groupId} 33 | alfresco-repository 34 | 35 | 36 | 37 | com.ceph 38 | rados 39 | 0.3.0 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /alfresco-ceph-rados/src/main/amp/config/alfresco/module/alfresco-ceph/alfresco-global.properties: -------------------------------------------------------------------------------- 1 | ## Ceph Configuration 2 | 3 | ceph.configFile=/etc/ceph/ceph.conf 4 | ceph.id=client.admin 5 | ceph.pool=alfresco 6 | ceph.clusterName=ceph 7 | -------------------------------------------------------------------------------- /alfresco-ceph-rados/src/main/amp/config/alfresco/module/alfresco-ceph/caching-context.xml.sample: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | 21 | 22 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 52 | 53 | 54 | 55 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | org.alfresco.repo.content.caching.cleanup.CachedContentCleanupJob 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 80 | 81 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | ${system.content.caching.contentCleanup.cronExpression} 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /alfresco-ceph-rados/src/main/amp/config/alfresco/module/alfresco-ceph/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.logger.fr.jeci.alfresco.ceph=INFO 2 | -------------------------------------------------------------------------------- /alfresco-ceph-rados/src/main/amp/config/alfresco/module/alfresco-ceph/module-context.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | 21 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /alfresco-ceph-rados/src/main/amp/module.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one or more 2 | # contributor license agreements. See the NOTICE file distributed with 3 | # this work for additional information regarding copyright ownership. 4 | # The ASF licenses this file to You under the Apache License, Version 2.0 5 | # (the "License"); you may not use this file except in compliance with 6 | # the License. You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | 17 | 18 | # SDK Sample module 19 | 20 | # ==== Beginning of Alfresco required/optional properties ====== # 21 | # NB: These properties are filtered at build time by Maven, single 22 | # sourcing from POM properties 23 | module.id=${project.artifactId} 24 | #module.aliases=myModule-123, my-module 25 | module.title=${project.name} 26 | module.description=${project.description} 27 | module.version=${project.version} 28 | 29 | # The following optional properties can be used to prevent the module from being added 30 | # to inappropriate versions of the WAR file. 31 | # module.repo.version.min=2.0 32 | # module.repo.version.max=2.1 33 | 34 | # FIXME: This dependencies should come out of mvn dependencies on amp 35 | 36 | # The following describe dependencies on other modules 37 | # Depends on net.sf.myproject.module.SupportModuleA version ${version} or later 38 | # module.depends.net.sf.myproject.module.SupportModuleA=${version}-* 39 | # Depends on net.sf.myproject.module.SupportModuleA version ${version} to 2.0 40 | # module.depends.net.sf.myproject.module.SupportModuleB=${version}-2.0 41 | # Depends on net.sf.myproject.module.SupportModuleC - any version 42 | # module.depends.net.sf.myproject.module.SupportModuleB=* 43 | 44 | 45 | # ==== End of Alfresco required/optional properties ======= # 46 | 47 | 48 | # ==== Beginning of module required properties/optional ====== # -------------------------------------------------------------------------------- /alfresco-ceph-rados/src/main/java/fr/jeci/alfresco/ceph/CephContentReader.java: -------------------------------------------------------------------------------- 1 | package fr.jeci.alfresco.ceph; 2 | 3 | /* Copyright 2016, 2017 - Jeci SARL - http://jeci.fr 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public License 16 | along with this program. If not, see http://www.gnu.org/licenses/. 17 | */ 18 | 19 | import java.io.IOException; 20 | import java.nio.channels.ReadableByteChannel; 21 | 22 | import org.alfresco.repo.content.AbstractContentReader; 23 | import org.alfresco.service.cmr.repository.ContentIOException; 24 | import org.alfresco.service.cmr.repository.ContentReader; 25 | import org.apache.commons.logging.Log; 26 | import org.apache.commons.logging.LogFactory; 27 | 28 | import com.ceph.rados.IoCTX; 29 | import com.ceph.rados.Rados; 30 | import com.ceph.rados.exceptions.RadosException; 31 | import com.ceph.rados.jna.RadosObjectInfo; 32 | 33 | public class CephContentReader extends AbstractContentReader { 34 | private static final Log logger = LogFactory.getLog(CephContentReader.class); 35 | 36 | private final Rados rados; 37 | private final String pool; 38 | private final String locator; 39 | 40 | public CephContentReader(Rados rados, String pool, String locator) throws IOException { 41 | super(locator); 42 | this.rados = rados; 43 | this.locator = locator; 44 | this.pool = pool; 45 | 46 | if (locator == null) { 47 | throw new IllegalArgumentException("locator is null"); 48 | } 49 | 50 | if (pool == null) { 51 | throw new IllegalArgumentException("pool is null"); 52 | } 53 | 54 | if (logger.isDebugEnabled()) { 55 | logger.debug("Ceph Content Reader for " + locator + " in " + pool); 56 | } 57 | 58 | } 59 | 60 | @Override 61 | public boolean exists() { 62 | IoCTX ioctx = null; 63 | try { 64 | ioctx = this.rados.ioCtxCreate(pool); 65 | RadosObjectInfo stat = ioctx.stat(locator); 66 | return stat != null; 67 | 68 | } catch (RadosException e) { 69 | logger.error(e.getMessage(), e); 70 | } finally { 71 | if (ioctx != null) { 72 | this.rados.ioCtxDestroy(ioctx); 73 | } 74 | } 75 | 76 | return false; 77 | } 78 | 79 | @Override 80 | public long getLastModified() { 81 | IoCTX ioctx = null; 82 | 83 | try { 84 | ioctx = this.rados.ioCtxCreate(this.pool); 85 | RadosObjectInfo stat = ioctx.stat(this.locator); 86 | 87 | if (stat != null) { 88 | return stat.getMtime(); 89 | } 90 | 91 | } catch (RadosException e) { 92 | logger.error(e.getMessage(), e); 93 | } finally { 94 | if (ioctx != null) { 95 | this.rados.ioCtxDestroy(ioctx); 96 | } 97 | } 98 | 99 | return 0L; 100 | } 101 | 102 | @Override 103 | public long getSize() { 104 | IoCTX ioctx = null; 105 | 106 | try { 107 | ioctx = this.rados.ioCtxCreate(this.pool); 108 | RadosObjectInfo stat = ioctx.stat(this.locator); 109 | 110 | if (stat != null) { 111 | return stat.getSize(); 112 | } 113 | 114 | } catch (RadosException e) { 115 | logger.error(e.getMessage(), e); 116 | } finally { 117 | if (ioctx != null) { 118 | this.rados.ioCtxDestroy(ioctx); 119 | } 120 | } 121 | 122 | return 0L; 123 | } 124 | 125 | @Override 126 | protected ContentReader createReader() { 127 | try { 128 | return new CephContentReader(this.rados, this.pool, this.locator); 129 | } catch (IOException e) { 130 | throw new ContentIOException(e.getMessage(), e); 131 | } 132 | } 133 | 134 | @Override 135 | protected ReadableByteChannel getDirectReadableChannel() { 136 | return new RadosReadableByteChannel(this.rados, this.pool, this.locator); 137 | } 138 | 139 | } 140 | -------------------------------------------------------------------------------- /alfresco-ceph-rados/src/main/java/fr/jeci/alfresco/ceph/CephContentWriter.java: -------------------------------------------------------------------------------- 1 | package fr.jeci.alfresco.ceph; 2 | 3 | /* Copyright 2016, 2017 - Jeci SARL - http://jeci.fr 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public License 16 | along with this program. If not, see http://www.gnu.org/licenses/. 17 | */ 18 | 19 | import java.io.IOException; 20 | import java.nio.channels.WritableByteChannel; 21 | 22 | import org.alfresco.repo.content.AbstractContentWriter; 23 | import org.alfresco.service.cmr.repository.ContentIOException; 24 | import org.alfresco.service.cmr.repository.ContentReader; 25 | 26 | import com.ceph.rados.Rados; 27 | 28 | public class CephContentWriter extends AbstractContentWriter { 29 | private final Rados rados; 30 | private final String pool; 31 | private final String locator; 32 | 33 | private final RadosWritableByteChannel channel; 34 | 35 | public CephContentWriter(Rados rados, String pool, String locator) { 36 | super(locator, null); 37 | this.rados = rados; 38 | this.pool = pool; 39 | this.locator = locator; 40 | 41 | if (locator == null) { 42 | throw new IllegalArgumentException("locator is null"); 43 | } 44 | 45 | if (pool == null) { 46 | throw new IllegalArgumentException("pool is null"); 47 | } 48 | this.channel = new RadosWritableByteChannel(rados, pool, locator); 49 | } 50 | 51 | @Override 52 | protected ContentReader createReader() { 53 | try { 54 | return new CephContentReader(rados, pool, locator); 55 | } catch (IOException e) { 56 | throw new ContentIOException(e.getMessage(), e); 57 | } 58 | } 59 | 60 | @Override 61 | protected WritableByteChannel getDirectWritableChannel() { 62 | return this.channel; 63 | } 64 | 65 | @Override 66 | public long getSize() { 67 | return this.channel.getOffset(); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /alfresco-ceph-rados/src/main/java/fr/jeci/alfresco/ceph/RadosReadableByteChannel.java: -------------------------------------------------------------------------------- 1 | package fr.jeci.alfresco.ceph; 2 | 3 | /* Copyright 2016, 2017 - Jeci SARL - http://jeci.fr 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public License 16 | along with this program. If not, see http://www.gnu.org/licenses/. 17 | */ 18 | 19 | import java.io.IOException; 20 | import java.nio.ByteBuffer; 21 | import java.nio.channels.ReadableByteChannel; 22 | import java.nio.channels.spi.AbstractInterruptibleChannel; 23 | 24 | import org.alfresco.service.cmr.repository.ContentIOException; 25 | import org.apache.commons.logging.Log; 26 | import org.apache.commons.logging.LogFactory; 27 | 28 | import com.ceph.rados.IoCTX; 29 | import com.ceph.rados.Rados; 30 | import com.ceph.rados.exceptions.RadosException; 31 | 32 | public class RadosReadableByteChannel extends AbstractInterruptibleChannel implements ReadableByteChannel { 33 | private static final Log logger = LogFactory.getLog(RadosReadableByteChannel.class); 34 | 35 | private static final int TRANSFER_SIZE = 8192; 36 | private byte[] buf = new byte[0]; 37 | private Object readLock = new Object(); 38 | private final String locator; 39 | 40 | private IoCTX io; 41 | private Rados rados; 42 | 43 | // Offest of byte read from rados 44 | private int offset = 0; 45 | 46 | public RadosReadableByteChannel(Rados rados, String pool, String locator) { 47 | this.rados = rados; 48 | this.locator = locator; 49 | 50 | if (locator == null) { 51 | throw new IllegalArgumentException("locator is null"); 52 | } 53 | 54 | try { 55 | this.io = this.rados.ioCtxCreate(pool); 56 | } catch (RadosException e) { 57 | throw new ContentIOException("Error creatinf IO Context", e); 58 | } 59 | } 60 | 61 | @Override 62 | public int read(ByteBuffer dst) throws IOException { 63 | int remaining = dst.remaining(); 64 | int totalRead = 0; 65 | int bytesRead = 0; 66 | synchronized (this.readLock) { 67 | long start = System.currentTimeMillis(); 68 | 69 | try { 70 | while (totalRead < remaining) { 71 | int bytesToRead = Math.min(remaining - totalRead, TRANSFER_SIZE); 72 | if (buf.length < bytesToRead) { 73 | buf = new byte[bytesToRead]; 74 | } 75 | 76 | try { 77 | begin(); 78 | 79 | bytesRead = this.io.read(this.locator, bytesToRead, this.offset, this.buf); 80 | this.offset += bytesRead; 81 | } finally { 82 | end(bytesRead >= 0); 83 | } 84 | 85 | // exit when error 86 | if (bytesRead < 0) { 87 | break; 88 | } 89 | 90 | totalRead += bytesRead; 91 | 92 | dst.put(buf, 0, bytesRead); 93 | 94 | // No more bytes to read, exit 95 | if (bytesRead < bytesToRead) { 96 | break; 97 | } 98 | 99 | } 100 | 101 | if (logger.isDebugEnabled()) { 102 | logger.debug("# Rados read " + this.locator + " " + totalRead + " bytes in " 103 | + (System.currentTimeMillis() - start) + " ms"); 104 | } 105 | 106 | if ((bytesRead <= 0) && (totalRead == 0)) { 107 | return -1; 108 | } 109 | } catch (RadosException e) { 110 | throw new IOException(e); 111 | } 112 | 113 | return totalRead; 114 | } 115 | } 116 | 117 | @Override 118 | protected void implCloseChannel() throws IOException { 119 | if (this.io != null) { 120 | this.rados.ioCtxDestroy(this.io); 121 | } 122 | } 123 | 124 | } 125 | -------------------------------------------------------------------------------- /alfresco-ceph-rados/src/main/java/fr/jeci/alfresco/ceph/RadosServiceImpl.java: -------------------------------------------------------------------------------- 1 | package fr.jeci.alfresco.ceph; 2 | 3 | /* Copyright 2016, 2017 - Jeci SARL - http://jeci.fr 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public License 16 | along with this program. If not, see http://www.gnu.org/licenses/. 17 | */ 18 | 19 | import java.io.File; 20 | import java.io.IOException; 21 | 22 | import org.alfresco.service.cmr.repository.ContentReader; 23 | import org.alfresco.service.cmr.repository.ContentWriter; 24 | import org.apache.commons.logging.Log; 25 | import org.apache.commons.logging.LogFactory; 26 | 27 | import com.ceph.rados.IoCTX; 28 | import com.ceph.rados.Rados; 29 | import com.ceph.rados.exceptions.RadosException; 30 | import com.ceph.rados.jna.RadosClusterInfo; 31 | 32 | import fr.jeci.alfresco.ObjectStorageService; 33 | 34 | public class RadosServiceImpl implements ObjectStorageService { 35 | private static final Log logger = LogFactory.getLog(RadosServiceImpl.class); 36 | 37 | private String configFile; 38 | private String id; 39 | private String pool; 40 | private String metadataPool; 41 | private String clusterName; 42 | 43 | private Rados rados; 44 | 45 | private int writebufferSize; 46 | private int readbufferSize; 47 | 48 | public void init() throws RadosException { 49 | if (logger.isInfoEnabled()) { 50 | logger.info("Config : " + this.configFile); 51 | logger.info("Pool : " + this.pool); 52 | logger.info("clusterName : " + this.clusterName); 53 | logger.info("id : " + this.id); 54 | } 55 | 56 | this.rados = new Rados(this.clusterName, this.id, 0); 57 | File file = new File(this.configFile); 58 | if (file.exists()) { 59 | if (logger.isDebugEnabled()) { 60 | logger.debug("Load Rados Conf " + this.configFile); 61 | } 62 | this.rados.confReadFile(file); 63 | } else { 64 | logger.error("File " + this.configFile + " not found"); 65 | } 66 | this.rados.connect(); 67 | logger.info(printRadosStats(rados)); 68 | } 69 | 70 | private String printRadosStats(Rados rados) throws RadosException { 71 | RadosClusterInfo stat = rados.clusterStat(); 72 | StringBuilder sb = new StringBuilder(); 73 | sb.append("Using RadosServiceImpl"); 74 | sb.append(" (").append(stat.kb).append("KB, ");// Cluster size 75 | sb.append(stat.kb_used * 100 / stat.kb).append("%, "); 76 | // sb.append(stat.kb_avail); // KB available 77 | // sb.append("KB, "); 78 | sb.append(stat.num_objects).append(")");// Number of objects 79 | return sb.toString(); 80 | } 81 | 82 | @Override 83 | public ContentReader getReader(String locator) throws IOException { 84 | return new CephContentReader(rados, pool, locator); 85 | } 86 | 87 | @Override 88 | public ContentWriter getWriter(String locator) { 89 | return new CephContentWriter(rados, pool, locator); 90 | } 91 | 92 | @Override 93 | public boolean isWriteSupported() { 94 | return true; 95 | } 96 | 97 | @Override 98 | public boolean delete(String locator) { 99 | IoCTX io = null; 100 | try { 101 | io = this.rados.ioCtxCreate(pool); 102 | io.remove(locator); 103 | 104 | return true; 105 | } catch (Exception e) { 106 | logger.error(e.getMessage(), e); 107 | return false; 108 | } finally { 109 | if (io != null) { 110 | this.rados.ioCtxDestroy(io); 111 | } 112 | } 113 | } 114 | 115 | public String getConfigFile() { 116 | return configFile; 117 | } 118 | 119 | public void setConfigFile(String configFile) { 120 | this.configFile = configFile; 121 | } 122 | 123 | public String getId() { 124 | return id; 125 | } 126 | 127 | public void setId(String id) { 128 | this.id = id; 129 | } 130 | 131 | @Override 132 | public String getContainer() { 133 | return pool; 134 | } 135 | 136 | public void setPool(String pool) { 137 | this.pool = pool; 138 | } 139 | 140 | public String getMetadataPool() { 141 | return metadataPool; 142 | } 143 | 144 | public void setMetadataPool(String metadataPool) { 145 | this.metadataPool = metadataPool; 146 | } 147 | 148 | public String getClusterName() { 149 | return clusterName; 150 | } 151 | 152 | public void setClusterName(String clusterName) { 153 | this.clusterName = clusterName; 154 | } 155 | 156 | public Rados getRados() { 157 | return rados; 158 | } 159 | 160 | public void setRados(Rados rados) { 161 | this.rados = rados; 162 | } 163 | 164 | public int getWritebufferSize() { 165 | return writebufferSize; 166 | } 167 | 168 | public void setWritebufferSize(int writebufferSize) { 169 | this.writebufferSize = writebufferSize; 170 | } 171 | 172 | public int getReadbufferSize() { 173 | return readbufferSize; 174 | } 175 | 176 | public void setReadbufferSize(int readbufferSize) { 177 | this.readbufferSize = readbufferSize; 178 | } 179 | 180 | } 181 | -------------------------------------------------------------------------------- /alfresco-ceph-rados/src/main/java/fr/jeci/alfresco/ceph/RadosWritableByteChannel.java: -------------------------------------------------------------------------------- 1 | package fr.jeci.alfresco.ceph; 2 | 3 | /* Copyright 2016, 2017 - Jeci SARL - http://jeci.fr 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public License 16 | along with this program. If not, see http://www.gnu.org/licenses/. 17 | */ 18 | 19 | import java.io.IOException; 20 | import java.nio.ByteBuffer; 21 | import java.nio.channels.WritableByteChannel; 22 | import java.nio.channels.spi.AbstractInterruptibleChannel; 23 | 24 | import org.alfresco.service.cmr.repository.ContentIOException; 25 | import org.apache.commons.logging.Log; 26 | import org.apache.commons.logging.LogFactory; 27 | 28 | import com.ceph.rados.IoCTX; 29 | import com.ceph.rados.Rados; 30 | import com.ceph.rados.exceptions.RadosException; 31 | 32 | public class RadosWritableByteChannel extends AbstractInterruptibleChannel implements WritableByteChannel { 33 | private static final Log logger = LogFactory.getLog(RadosWritableByteChannel.class); 34 | 35 | private IoCTX io = null; 36 | 37 | private byte[] buf = new byte[0]; 38 | // 128k 39 | private static final int TRANSFER_SIZE = 131072; 40 | private Object writeLock = new Object(); 41 | private final String locator; 42 | private final Rados rados; 43 | private long offset = 0L; 44 | 45 | public RadosWritableByteChannel(Rados rados, String pool, String locator) { 46 | this.locator = locator; 47 | this.rados = rados; 48 | try { 49 | this.io = this.rados.ioCtxCreate(pool); 50 | } catch (RadosException e) { 51 | throw new ContentIOException("Error creatinf IO Context", e); 52 | } 53 | } 54 | 55 | @Override 56 | public int write(ByteBuffer src) throws IOException { 57 | int len = src.remaining(); 58 | int totalWritten = 0; 59 | synchronized (this.writeLock) { 60 | long start = System.currentTimeMillis(); 61 | 62 | try { 63 | while (totalWritten < len) { 64 | int bytesToWrite = Math.min((len - totalWritten), TRANSFER_SIZE); 65 | if (this.buf.length != bytesToWrite) { 66 | this.buf = new byte[bytesToWrite]; 67 | } 68 | 69 | src.get(this.buf, 0, bytesToWrite); 70 | try { 71 | begin(); 72 | this.io.write(this.locator, this.buf, this.offset); 73 | this.offset += bytesToWrite; 74 | } finally { 75 | end(bytesToWrite > 0); 76 | } 77 | totalWritten += bytesToWrite; 78 | } 79 | 80 | if (this.offset == 0) { 81 | /* Create empty object */ 82 | this.io.write(this.locator, "", this.offset); 83 | } 84 | 85 | if (logger.isDebugEnabled()) { 86 | logger.debug("# Rados write " + this.locator + " " + totalWritten + " bytes in " 87 | + (System.currentTimeMillis() - start) + " ms"); 88 | } 89 | 90 | } catch (RadosException e) { 91 | throw new IOException(e); 92 | } 93 | return totalWritten; 94 | } 95 | } 96 | 97 | @Override 98 | protected void implCloseChannel() throws IOException { 99 | if (this.io != null) { 100 | this.rados.ioCtxDestroy(this.io); 101 | } 102 | } 103 | 104 | public long getOffset() { 105 | return offset; 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /alfresco-object-storage-commons/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | alfresco-object-storage-commons 6 | 1.0.0 7 | Object Storage Commons Libs 8 | jar 9 | Object Storage Commons Libs for Alfresco connectors 10 | 11 | 12 | fr.jeci.alfresco-object-storage 13 | alfresco-object-storage-parent 14 | 1.0.0 15 | 16 | 17 | 18 | 19 | GNU Lesser General Public License v3.0 or later 20 | http://www.gnu.org/licenses/lgpl-3.0-standalone.html 21 | 22 | 23 | 24 | 25 | 26 | ${alfresco.groupId} 27 | alfresco-repository 28 | 29 | 30 | 31 | io.netty 32 | netty-buffer 33 | 4.1.4.Final 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /alfresco-object-storage-commons/src/main/java/fr/jeci/alfresco/ByteBufWritableByteChannel.java: -------------------------------------------------------------------------------- 1 | package fr.jeci.alfresco; 2 | 3 | /* Copyright 2016, 2017 - Jeci SARL - http://jeci.fr 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public License 16 | along with this program. If not, see http://www.gnu.org/licenses/. 17 | */ 18 | 19 | import java.io.IOException; 20 | import java.nio.ByteBuffer; 21 | import java.nio.channels.WritableByteChannel; 22 | import java.nio.channels.spi.AbstractInterruptibleChannel; 23 | 24 | import io.netty.buffer.ByteBuf; 25 | import io.netty.buffer.Unpooled; 26 | 27 | public abstract class ByteBufWritableByteChannel extends AbstractInterruptibleChannel implements WritableByteChannel { 28 | 29 | private ByteBuf buffer = Unpooled.buffer(0, Integer.MAX_VALUE); 30 | 31 | private long size = 0L; 32 | 33 | @Override 34 | public int write(ByteBuffer src) throws IOException { 35 | int start = this.buffer.writerIndex(); 36 | this.buffer.writeBytes(src); 37 | int written = this.buffer.writerIndex() - start; 38 | this.size += written; 39 | return written; 40 | } 41 | 42 | @Override 43 | protected void implCloseChannel() throws IOException { 44 | try { 45 | implCloseChannel(this.buffer); 46 | } finally { 47 | this.buffer.release(); 48 | } 49 | } 50 | 51 | /** 52 | * @return Total byte written 53 | */ 54 | public long getSize() { 55 | return size; 56 | } 57 | 58 | protected abstract void implCloseChannel(ByteBuf buffer); 59 | 60 | } -------------------------------------------------------------------------------- /alfresco-object-storage-commons/src/main/java/fr/jeci/alfresco/ObjectStorageContentStore.java: -------------------------------------------------------------------------------- 1 | package fr.jeci.alfresco; 2 | 3 | /* Copyright 2016, 2017 - Jeci SARL - http://jeci.fr 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public License 16 | along with this program. If not, see http://www.gnu.org/licenses/. 17 | */ 18 | 19 | import java.io.IOException; 20 | import java.io.Serializable; 21 | import java.util.Collections; 22 | import java.util.concurrent.locks.ReentrantReadWriteLock; 23 | import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; 24 | 25 | import org.alfresco.repo.content.AbstractContentStore; 26 | import org.alfresco.repo.content.ContentStoreCreatedEvent; 27 | import org.alfresco.service.cmr.repository.ContentReader; 28 | import org.alfresco.service.cmr.repository.ContentWriter; 29 | import org.alfresco.util.GUID; 30 | import org.apache.commons.lang3.StringUtils; 31 | import org.apache.commons.logging.Log; 32 | import org.apache.commons.logging.LogFactory; 33 | import org.springframework.context.ApplicationContext; 34 | import org.springframework.context.ApplicationContextAware; 35 | import org.springframework.context.ApplicationEvent; 36 | import org.springframework.context.ApplicationListener; 37 | import org.springframework.context.event.ContextRefreshedEvent; 38 | 39 | /** 40 | * Common ContentStore to all commector implementation. 41 | * 42 | * @author jeremie.lesage 43 | * 44 | */ 45 | public class ObjectStorageContentStore extends AbstractContentStore 46 | implements ApplicationContextAware, ApplicationListener { 47 | private static final Log logger = LogFactory.getLog(ObjectStorageContentStore.class); 48 | 49 | // NUM_LOCKS absolutely must be a power of 2 for the use of locks to be 50 | // evenly balanced 51 | private static final int NUM_LOCKS = 256; 52 | private static final ReentrantReadWriteLock[] LOCKS; 53 | 54 | private ObjectStorageService objectStorageService; 55 | private ApplicationContext applicationContext; 56 | 57 | private String storeProtocole = null; 58 | 59 | static { 60 | LOCKS = new ReentrantReadWriteLock[NUM_LOCKS]; 61 | for (int i = 0; i < NUM_LOCKS; i++) { 62 | LOCKS[i] = new ReentrantReadWriteLock(); 63 | } 64 | } 65 | 66 | @Override 67 | public boolean isWriteSupported() { 68 | return this.objectStorageService.isWriteSupported(); 69 | } 70 | 71 | @Override 72 | public ContentReader getReader(String contentUrl) { 73 | if (logger.isDebugEnabled()) { 74 | logger.debug(String.format("Content Reader for %s", contentUrl)); 75 | } 76 | 77 | // Use pool of locks - which one is determined by a hash of the URL. 78 | // This will stop the content from being read/cached multiple times from 79 | // the backing store 80 | // when it should only be read once - cached versions should be returned 81 | // after that. 82 | ReadLock readLock = readWriteLock(contentUrl).readLock(); 83 | readLock.lock(); 84 | try { 85 | return this.objectStorageService.getReader(contentUrl); 86 | } catch (IOException e) { 87 | logger.error(e.getMessage(), e); 88 | } finally { 89 | readLock.unlock(); 90 | } 91 | 92 | return null; 93 | } 94 | 95 | @Override 96 | protected ContentWriter getWriterInternal(final ContentReader existingContentReader, final String newContentUrl) { 97 | String contentUrl = newContentUrl; 98 | if (StringUtils.isBlank(contentUrl)) { 99 | contentUrl = createNewUrl(); 100 | } 101 | if (logger.isDebugEnabled()) { 102 | logger.debug(String.format("ContentWriter for %s", contentUrl)); 103 | } 104 | try { 105 | return this.objectStorageService.getWriter(contentUrl); 106 | } catch (IOException e) { 107 | logger.error(e.getMessage(), e); 108 | } 109 | 110 | return null; 111 | } 112 | 113 | @Override 114 | public boolean isContentUrlSupported(String contentUrl) { 115 | String startUrl = String.format("%s://%s/", this.storeProtocole, this.objectStorageService.getContainer()); 116 | return contentUrl.startsWith(startUrl); 117 | } 118 | 119 | protected String createNewUrl() { 120 | return String.format("%s://%s/%s", this.storeProtocole, this.objectStorageService.getContainer(), 121 | GUID.generate()); 122 | } 123 | 124 | @Override 125 | public boolean delete(String contentUrl) { 126 | if (logger.isDebugEnabled()) { 127 | logger.debug(String.format("Delete %s", contentUrl)); 128 | } 129 | ReentrantReadWriteLock readWriteLock = readWriteLock(contentUrl); 130 | ReadLock readLock = readWriteLock.readLock(); 131 | readLock.lock(); 132 | try { 133 | return this.objectStorageService.delete(contentUrl); 134 | } finally { 135 | readLock.unlock(); 136 | } 137 | } 138 | 139 | @Override 140 | public void onApplicationEvent(ApplicationEvent event) { 141 | // Once the context has been refreshed, we tell other interested beans 142 | // about the existence of this content store 143 | // (e.g. for monitoring purposes) 144 | if (event instanceof ContextRefreshedEvent && event.getSource() == this.applicationContext) { 145 | ApplicationContext context = ((ContextRefreshedEvent) event).getApplicationContext(); 146 | context.publishEvent(new ContentStoreCreatedEvent(this, Collections.emptyMap())); 147 | } 148 | } 149 | 150 | /** 151 | * Get a ReentrantReadWriteLock for a given URL. The lock is from a pool 152 | * rather than per URL, so some contention is expected. 153 | * 154 | * @param url 155 | * String 156 | * @return ReentrantReadWriteLock 157 | */ 158 | public ReentrantReadWriteLock readWriteLock(String url) { 159 | return LOCKS[lockIndex(url)]; 160 | } 161 | 162 | private int lockIndex(String url) { 163 | return url.hashCode() & (NUM_LOCKS - 1); 164 | } 165 | 166 | @Override 167 | public void setApplicationContext(ApplicationContext applicationContext) { 168 | this.applicationContext = applicationContext; 169 | } 170 | 171 | public void setObjectStorageService(ObjectStorageService objectStorageService) { 172 | this.objectStorageService = objectStorageService; 173 | } 174 | 175 | public void setStoreProtocole(String storeProtocole) { 176 | this.storeProtocole = storeProtocole; 177 | } 178 | 179 | } 180 | -------------------------------------------------------------------------------- /alfresco-object-storage-commons/src/main/java/fr/jeci/alfresco/ObjectStorageService.java: -------------------------------------------------------------------------------- 1 | package fr.jeci.alfresco; 2 | 3 | /* Copyright 2016, 2017 - Jeci SARL - http://jeci.fr 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public License 16 | along with this program. If not, see http://www.gnu.org/licenses/. 17 | */ 18 | 19 | import java.io.IOException; 20 | 21 | import org.alfresco.service.cmr.repository.ContentReader; 22 | import org.alfresco.service.cmr.repository.ContentWriter; 23 | 24 | /** 25 | * Common Interface for all ObjectStorage implementation 26 | * 27 | * @author jeremie.lesage 28 | * 29 | */ 30 | public interface ObjectStorageService { 31 | 32 | ContentReader getReader(String contentUrl) throws IOException; 33 | 34 | boolean isWriteSupported(); 35 | 36 | boolean delete(String contentUrl); 37 | 38 | ContentWriter getWriter(String contentUrl) throws IOException; 39 | 40 | /** 41 | * Storage Container or Pool 42 | * 43 | * @return 44 | */ 45 | String getContainer(); 46 | 47 | } 48 | -------------------------------------------------------------------------------- /alfresco-openio/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM jeci/alfresco-platform:5.2.f 2 | MAINTAINER Jeremie Lesage 3 | 4 | COPY target/alfresco-openio-*.amp /root/amp/ 5 | 6 | RUN java -jar /root/alfresco-mmt.jar install /root/amp/ /usr/local/tomcat/webapps/alfresco -nobackup -directory -force \ 7 | && rm -r /usr/local/tomcat/webapps/alfresco/WEB-INF/classes/alfresco/module/backup 8 | 9 | COPY assets/alfresco-global.properties /usr/local/tomcat/shared/classes/alfresco-global.properties 10 | -------------------------------------------------------------------------------- /alfresco-openio/assets/alfresco-global.properties: -------------------------------------------------------------------------------- 1 | ## OpenIO Configuration 2 | 3 | openio.target=http://openio:6006 4 | openio.namespace=OPENIO 5 | openio.account=alfresco 6 | openio.container=alfresco 7 | -------------------------------------------------------------------------------- /alfresco-openio/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | # CONFIGURATION POUR VPS SSD 3 de OVH 3 | # 2vCores, 8Go RAM, 40Go SSD 4 | volumes: 5 | alf_logs: 6 | alf_data: 7 | share_logs: 8 | solr_logs: 9 | solr_data: 10 | pgsql_data: 11 | 12 | 13 | networks: 14 | alf-share: 15 | internal: 16 | driver: bridge 17 | ipam: 18 | driver: default 19 | config: 20 | - subnet: 192.168.168.0/24 21 | gateway: 192.168.168.1 22 | 23 | services: 24 | alfresco: 25 | image: jeci/alfresco-platform-openio 26 | environment: 27 | CATALINA_OPTS: "-Xms512m -Xmx1G -XX:+UseConcMarkSweepGC " 28 | depends_on: 29 | - postgresql 30 | - libreoffice 31 | - openio 32 | ulimits: 33 | nproc: 65535 34 | nofile: 35 | soft: 20000 36 | hard: 40000 37 | networks: 38 | - alf-share 39 | - internal 40 | ports: 41 | - "8081:8080" 42 | volumes: 43 | - "alf_logs:/usr/local/tomcat/logs/" 44 | - "alf_data:/opt/alf_data" 45 | tmpfs: 46 | - /tmp 47 | - /usr/local/tomcat/temp/:exec 48 | - /usr/local/tomcat/work/ 49 | 50 | share: 51 | image: jeci/alfresco-share:5.2.e 52 | restart: always 53 | environment: 54 | CATALINA_OPTS: "-Xms512m -Xmx1G -XX:+UseConcMarkSweepGC " 55 | depends_on: 56 | - alfresco 57 | networks: 58 | - alf-share 59 | ports: 60 | - "8080:8080" 61 | volumes: 62 | - "share_logs:/usr/local/tomcat/logs/" 63 | tmpfs: 64 | - /tmp 65 | - /usr/local/tomcat/temp/ 66 | - /usr/local/tomcat/work/ 67 | 68 | solr: 69 | image: jeci/alfresco-solr:5.2.f 70 | environment: 71 | CATALINA_OPTS: "-Xms512m -Xmx1G -XX:+UseG1GC -XX:+ParallelRefProcEnabled -XX:G1HeapRegionSize=8m -XX:MaxGCPauseMillis=200 " 72 | depends_on: 73 | - alfresco 74 | ulimits: 75 | nproc: 65535 76 | nofile: 77 | soft: 20000 78 | hard: 40000 79 | networks: 80 | - internal 81 | volumes: 82 | - "solr_logs:/usr/local/tomcat/logs/" 83 | - "solr_data:/opt/solr_data" 84 | tmpfs: 85 | - /tmp 86 | - /usr/local/tomcat/temp/ 87 | - /usr/local/tomcat/work/ 88 | 89 | postgresql: 90 | image: postgres:9.4 91 | environment: 92 | - POSTGRES_DB=alfresco 93 | - POSTGRES_PASSWORD=alfresco 94 | - POSTGRES_USER=alfresco 95 | networks: 96 | - internal 97 | volumes: 98 | - "pgsql_data:/var/lib/postgresql/data" 99 | 100 | libreoffice: 101 | image: jeci/alfresco-libreoffice:5.2.7 102 | restart: always 103 | user: root 104 | networks: 105 | - internal 106 | 107 | openio: 108 | image: openio/sds 109 | container_name: openio-service 110 | environment: 111 | OIO_NS: OPENIO 112 | OIO_ACCOUNT: alfresco 113 | OPENIO_IPADDR: 192.168.168.10 114 | networks: 115 | internal: 116 | ipv4_address: 192.168.168.10 117 | expose: 118 | - "6006" 119 | stdin_open: true 120 | tty: true 121 | -------------------------------------------------------------------------------- /alfresco-openio/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | alfresco-openio 6 | 1.0 7 | OpenIO Connector for Alfresco 8 | amp 9 | OpenIO module connector for Alfresco 10 | 11 | 12 | fr.jeci.alfresco-object-storage 13 | alfresco-object-storage-parent 14 | 1.0.0 15 | 16 | 17 | 18 | 19 | GNU Lesser General Public License v3.0 or later 20 | http://www.gnu.org/licenses/lgpl-3.0-standalone.html 21 | 22 | 23 | 24 | 25 | 26 | fr.jeci.alfresco-object-storage 27 | alfresco-object-storage-commons 28 | 1.0.0 29 | 30 | 31 | 32 | ${alfresco.groupId} 33 | alfresco-repository 34 | 35 | 36 | 37 | io.openio.sds 38 | openio-api 39 | 0.4.0 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /alfresco-openio/src/main/amp/config/alfresco/module/alfresco-openio/alfresco-global.properties: -------------------------------------------------------------------------------- 1 | ## OpenIO Configuration 2 | 3 | openio.target=http://127.0.0.1:6006 4 | openio.namespace=OPENIO 5 | openio.account=alfresco 6 | openio.container=alfresco 7 | -------------------------------------------------------------------------------- /alfresco-openio/src/main/amp/config/alfresco/module/alfresco-openio/caching-context.xml.sample: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | 21 | 22 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 43 | 44 | 45 | 46 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | org.alfresco.repo.content.caching.cleanup.CachedContentCleanupJob 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 71 | 72 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | ${system.content.caching.contentCleanup.cronExpression} 87 | 88 | 89 | 90 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /alfresco-openio/src/main/amp/config/alfresco/module/alfresco-openio/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.logger.fr.jeci.alfresco.openio=INFO 2 | -------------------------------------------------------------------------------- /alfresco-openio/src/main/amp/config/alfresco/module/alfresco-openio/module-context.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | 21 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /alfresco-openio/src/main/amp/module.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one or more 2 | # contributor license agreements. See the NOTICE file distributed with 3 | # this work for additional information regarding copyright ownership. 4 | # The ASF licenses this file to You under the Apache License, Version 2.0 5 | # (the "License"); you may not use this file except in compliance with 6 | # the License. You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | 17 | 18 | # SDK Sample module 19 | 20 | # ==== Beginning of Alfresco required/optional properties ====== # 21 | # NB: These properties are filtered at build time by Maven, single 22 | # sourcing from POM properties 23 | module.id=${project.artifactId} 24 | #module.aliases=myModule-123, my-module 25 | module.title=${project.name} 26 | module.description=${project.description} 27 | module.version=${project.version} 28 | 29 | # The following optional properties can be used to prevent the module from being added 30 | # to inappropriate versions of the WAR file. 31 | # module.repo.version.min=2.0 32 | # module.repo.version.max=2.1 33 | 34 | # FIXME: This dependencies should come out of mvn dependencies on amp 35 | 36 | # The following describe dependencies on other modules 37 | # Depends on net.sf.myproject.module.SupportModuleA version ${version} or later 38 | # module.depends.net.sf.myproject.module.SupportModuleA=${version}-* 39 | # Depends on net.sf.myproject.module.SupportModuleA version ${version} to 2.0 40 | # module.depends.net.sf.myproject.module.SupportModuleB=${version}-2.0 41 | # Depends on net.sf.myproject.module.SupportModuleC - any version 42 | # module.depends.net.sf.myproject.module.SupportModuleB=* 43 | 44 | 45 | # ==== End of Alfresco required/optional properties ======= # 46 | 47 | 48 | # ==== Beginning of module required properties/optional ====== # -------------------------------------------------------------------------------- /alfresco-openio/src/main/java/fr/jeci/alfresco/openio/OpenIOChannel.java: -------------------------------------------------------------------------------- 1 | package fr.jeci.alfresco.openio; 2 | 3 | /* Copyright 2016, 2017 - Jeci SARL - http://jeci.fr 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public License 16 | along with this program. If not, see http://www.gnu.org/licenses/. 17 | */ 18 | 19 | import fr.jeci.alfresco.ByteBufWritableByteChannel; 20 | import io.netty.buffer.ByteBuf; 21 | import io.netty.buffer.ByteBufInputStream; 22 | import io.openio.sds.Client; 23 | import io.openio.sds.models.OioUrl; 24 | 25 | public class OpenIOChannel extends ByteBufWritableByteChannel { 26 | 27 | private Client client; 28 | private OioUrl oioUrl; 29 | 30 | public OpenIOChannel(Client client, OioUrl oioUrl) { 31 | this.client = client; 32 | this.oioUrl = oioUrl; 33 | } 34 | 35 | @Override 36 | protected void implCloseChannel(ByteBuf buffer) { 37 | long size = (long) (buffer.writerIndex() - buffer.readerIndex()); 38 | this.client.putObject(oioUrl, size, new ByteBufInputStream(buffer)); 39 | } 40 | 41 | } -------------------------------------------------------------------------------- /alfresco-openio/src/main/java/fr/jeci/alfresco/openio/OpenIOContentReader.java: -------------------------------------------------------------------------------- 1 | package fr.jeci.alfresco.openio; 2 | 3 | /* Copyright 2016, 2017 - Jeci SARL - http://jeci.fr 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public License 16 | along with this program. If not, see http://www.gnu.org/licenses/. 17 | */ 18 | 19 | import java.nio.channels.Channels; 20 | import java.nio.channels.ReadableByteChannel; 21 | 22 | import org.alfresco.repo.content.AbstractContentReader; 23 | import org.alfresco.service.cmr.repository.ContentIOException; 24 | import org.alfresco.service.cmr.repository.ContentReader; 25 | import org.apache.commons.logging.Log; 26 | import org.apache.commons.logging.LogFactory; 27 | 28 | import io.openio.sds.Client; 29 | import io.openio.sds.models.ObjectInfo; 30 | import io.openio.sds.models.OioUrl; 31 | 32 | /** 33 | * Created by manens on 23/07/16. 34 | */ 35 | public class OpenIOContentReader extends AbstractContentReader { 36 | private static final Log logger = LogFactory.getLog(OpenIOContentReader.class); 37 | 38 | private Client client; 39 | private OioUrl oioUrl; 40 | 41 | protected OpenIOContentReader(Client client, OioUrl urlFile) { 42 | super(urlFile.object()); 43 | this.client = client; 44 | this.oioUrl = urlFile; 45 | } 46 | 47 | @Override 48 | protected ContentReader createReader() { 49 | if (logger.isDebugEnabled()) { 50 | logger.debug("Called createReader for contentUrl -> " + getContentUrl()); 51 | } 52 | return new OpenIOContentReader(this.client, this.oioUrl); 53 | } 54 | 55 | @Override 56 | protected ReadableByteChannel getDirectReadableChannel() { 57 | if (!exists()) { 58 | throw new ContentIOException("Content object does not exist on OpenIO"); 59 | } 60 | 61 | try { 62 | final ObjectInfo fileObjectMetadata = client.getObjectInfo(this.oioUrl); 63 | return Channels.newChannel(this.client.downloadObject(fileObjectMetadata)); 64 | } catch (Exception e) { 65 | throw new ContentIOException("Unable to retrieve content object from OpenIO", e); 66 | } 67 | 68 | } 69 | 70 | @Override 71 | public boolean exists() { 72 | return client.getObjectInfo(this.oioUrl) != null; 73 | } 74 | 75 | @Override 76 | public long getLastModified() { 77 | if (!exists()) { 78 | return 0L; 79 | } 80 | 81 | final ObjectInfo fileObjectMetadata = client.getObjectInfo(this.oioUrl); 82 | return fileObjectMetadata.ctime(); 83 | } 84 | 85 | @Override 86 | public long getSize() { 87 | if (!exists()) { 88 | return 0L; 89 | } 90 | 91 | final ObjectInfo fileObjectMetadata = client.getObjectInfo(this.oioUrl); 92 | return fileObjectMetadata.size(); 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /alfresco-openio/src/main/java/fr/jeci/alfresco/openio/OpenIOContentWriter.java: -------------------------------------------------------------------------------- 1 | package fr.jeci.alfresco.openio; 2 | 3 | /* Copyright 2016, 2017 - Jeci SARL - http://jeci.fr 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public License 16 | along with this program. If not, see http://www.gnu.org/licenses/. 17 | */ 18 | 19 | import java.nio.channels.WritableByteChannel; 20 | 21 | import org.alfresco.repo.content.AbstractContentWriter; 22 | import org.alfresco.service.cmr.repository.ContentReader; 23 | 24 | import io.openio.sds.Client; 25 | import io.openio.sds.models.OioUrl; 26 | 27 | /** 28 | * Created by manens on 23/07/16. 29 | */ 30 | public class OpenIOContentWriter extends AbstractContentWriter { 31 | private Client client; 32 | private OioUrl oioUrl; 33 | 34 | private final OpenIOChannel channel; 35 | 36 | protected OpenIOContentWriter(Client client, OioUrl urlFile) { 37 | super(urlFile.object(), null); 38 | this.client = client; 39 | this.oioUrl = urlFile; 40 | 41 | this.channel = new OpenIOChannel(this.client, this.oioUrl); 42 | } 43 | 44 | @Override 45 | protected ContentReader createReader() { 46 | return new OpenIOContentReader(this.client, this.oioUrl); 47 | } 48 | 49 | @Override 50 | protected WritableByteChannel getDirectWritableChannel() { 51 | return this.channel; 52 | } 53 | 54 | @Override 55 | public long getSize() { 56 | return this.channel.getSize(); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /alfresco-openio/src/main/java/fr/jeci/alfresco/openio/OpenIOServiceImpl.java: -------------------------------------------------------------------------------- 1 | package fr.jeci.alfresco.openio; 2 | 3 | /* Copyright 2016, 2017 - Jeci SARL - http://jeci.fr 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public License 16 | along with this program. If not, see http://www.gnu.org/licenses/. 17 | */ 18 | 19 | import java.io.IOException; 20 | 21 | import org.alfresco.service.cmr.repository.ContentReader; 22 | import org.alfresco.service.cmr.repository.ContentWriter; 23 | import org.apache.commons.logging.Log; 24 | import org.apache.commons.logging.LogFactory; 25 | 26 | import fr.jeci.alfresco.ObjectStorageService; 27 | import io.openio.sds.Client; 28 | import io.openio.sds.ClientBuilder; 29 | import io.openio.sds.Settings; 30 | import io.openio.sds.models.OioUrl; 31 | 32 | public class OpenIOServiceImpl implements ObjectStorageService { 33 | private static final Log logger = LogFactory.getLog(OpenIOServiceImpl.class); 34 | 35 | private String target; 36 | private String namespace; 37 | private String account; 38 | private Client client; 39 | private String container; 40 | 41 | public void init() { 42 | Settings settings = new Settings(); 43 | settings.proxy().ns(namespace).url(target); 44 | client = ClientBuilder.newClient(settings); 45 | } 46 | 47 | @Override 48 | public boolean isWriteSupported() { 49 | // this.container.getcontainerWritePermission() 50 | return true; 51 | } 52 | 53 | @Override 54 | public ContentReader getReader(String contentUrl) throws IOException { 55 | if (logger.isDebugEnabled()) { 56 | logger.debug("GETTING OBJECT - BUCKET: " + container + " KEY: " + contentUrl); 57 | } 58 | OioUrl urlFile = OioUrl.url(account, container, contentUrl); 59 | return new OpenIOContentReader(this.client, urlFile); 60 | } 61 | 62 | @Override 63 | public ContentWriter getWriter(String contentUrl) throws IOException { 64 | OioUrl urlFile = OioUrl.url(account, container, contentUrl); 65 | return new OpenIOContentWriter(client, urlFile); 66 | } 67 | 68 | @Override 69 | public boolean delete(String contentUrl) { 70 | try { 71 | OioUrl urlFile = OioUrl.url(account, container, contentUrl); 72 | client.deleteObject(urlFile); 73 | if (logger.isDebugEnabled()) { 74 | logger.debug("Deleting object from OpenIO with url: " + contentUrl); 75 | } 76 | return true; 77 | } catch (Exception e) { 78 | logger.error("Error deleting OpenIO Object", e); 79 | } 80 | return false; 81 | } 82 | 83 | public String getTarget() { 84 | return target; 85 | } 86 | 87 | public void setTarget(String target) { 88 | this.target = target; 89 | } 90 | 91 | public String getNamespace() { 92 | return namespace; 93 | } 94 | 95 | public void setNamespace(String namespace) { 96 | this.namespace = namespace; 97 | } 98 | 99 | public String getAccount() { 100 | return account; 101 | } 102 | 103 | public void setAccount(String account) { 104 | this.account = account; 105 | } 106 | 107 | public Client getClient() { 108 | return client; 109 | } 110 | 111 | public void setClient(Client client) { 112 | this.client = client; 113 | } 114 | 115 | @Override 116 | public String getContainer() { 117 | return container; 118 | } 119 | 120 | public void setContainer(String container) { 121 | this.container = container; 122 | } 123 | 124 | } 125 | -------------------------------------------------------------------------------- /alfresco-swift/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM jeci/alfresco-platform:5.2.f 2 | MAINTAINER Jeremie Lesage 3 | 4 | COPY target/alfresco-swift-*.amp /root/amp/ 5 | 6 | RUN java -jar /root/alfresco-mmt.jar install /root/amp/ /usr/local/tomcat/webapps/alfresco -nobackup -directory -force \ 7 | && rm -r /usr/local/tomcat/webapps/alfresco/WEB-INF/classes/alfresco/module/backup 8 | 9 | COPY assets/alfresco-global.properties /usr/local/tomcat/shared/classes/alfresco-global.properties 10 | -------------------------------------------------------------------------------- /alfresco-swift/assets/alfresco-global.properties: -------------------------------------------------------------------------------- 1 | ## Swift Configuration 2 | 3 | swift.username=user:swift 4 | swift.password=abcdefghijklmnop 5 | swift.url=https://s3.example.org/auth/1.0 6 | swift.tenantId= 7 | swift.tenantName= 8 | swift.containerName=alfresco 9 | -------------------------------------------------------------------------------- /alfresco-swift/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | alfresco-swift 6 | 1.0 7 | Swift Connector for Alfresco 8 | amp 9 | OpenStack Swift module connector for Alfresco 10 | 11 | 12 | fr.jeci.alfresco-object-storage 13 | alfresco-object-storage-parent 14 | 1.0.0 15 | 16 | 17 | 18 | 19 | GNU Lesser General Public License v3.0 or later 20 | http://www.gnu.org/licenses/lgpl-3.0-standalone.html 21 | 22 | 23 | 24 | 25 | 26 | fr.jeci.alfresco-object-storage 27 | alfresco-object-storage-commons 28 | 1.0.0 29 | 30 | 31 | 32 | ${alfresco.groupId} 33 | alfresco-repository 34 | 35 | 36 | 37 | org.javaswift 38 | joss 39 | 0.9.7 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /alfresco-swift/src/main/amp/config/alfresco/module/alfresco-swift/alfresco-global.properties: -------------------------------------------------------------------------------- 1 | ## Swift Configuration 2 | 3 | swift.username=user:swift 4 | swift.password=abcdefghijklmnop 5 | swift.url=https://s3.example.org/auth/1.0 6 | swift.tenantId= 7 | swift.tenantName= 8 | swift.containerName=alfresco 9 | -------------------------------------------------------------------------------- /alfresco-swift/src/main/amp/config/alfresco/module/alfresco-swift/caching-context.xml.sample: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | 21 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 53 | 54 | 55 | 56 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | org.alfresco.repo.content.caching.cleanup.CachedContentCleanupJob 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 81 | 82 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | ${system.content.caching.contentCleanup.cronExpression} 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /alfresco-swift/src/main/amp/config/alfresco/module/alfresco-swift/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.logger.fr.jeci.alfresco.swift=INFO 2 | -------------------------------------------------------------------------------- /alfresco-swift/src/main/amp/config/alfresco/module/alfresco-swift/module-context.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | 21 | 22 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /alfresco-swift/src/main/amp/module.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one or more 2 | # contributor license agreements. See the NOTICE file distributed with 3 | # this work for additional information regarding copyright ownership. 4 | # The ASF licenses this file to You under the Apache License, Version 2.0 5 | # (the "License"); you may not use this file except in compliance with 6 | # the License. You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | 17 | 18 | # SDK Sample module 19 | 20 | # ==== Beginning of Alfresco required/optional properties ====== # 21 | # NB: These properties are filtered at build time by Maven, single 22 | # sourcing from POM properties 23 | module.id=${project.artifactId} 24 | #module.aliases=myModule-123, my-module 25 | module.title=${project.name} 26 | module.description=${project.description} 27 | module.version=${project.version} 28 | 29 | # The following optional properties can be used to prevent the module from being added 30 | # to inappropriate versions of the WAR file. 31 | # module.repo.version.min=2.0 32 | # module.repo.version.max=2.1 33 | 34 | # FIXME: This dependencies should come out of mvn dependencies on amp 35 | 36 | # The following describe dependencies on other modules 37 | # Depends on net.sf.myproject.module.SupportModuleA version ${version} or later 38 | # module.depends.net.sf.myproject.module.SupportModuleA=${version}-* 39 | # Depends on net.sf.myproject.module.SupportModuleA version ${version} to 2.0 40 | # module.depends.net.sf.myproject.module.SupportModuleB=${version}-2.0 41 | # Depends on net.sf.myproject.module.SupportModuleC - any version 42 | # module.depends.net.sf.myproject.module.SupportModuleB=* 43 | 44 | 45 | # ==== End of Alfresco required/optional properties ======= # 46 | 47 | 48 | # ==== Beginning of module required properties/optional ====== # -------------------------------------------------------------------------------- /alfresco-swift/src/main/java/fr/jeci/alfresco/swift/SwiftChannel.java: -------------------------------------------------------------------------------- 1 | package fr.jeci.alfresco.swift; 2 | 3 | /* Copyright 2016, 2017 - Jeci SARL - http://jeci.fr 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public License 16 | along with this program. If not, see http://www.gnu.org/licenses/. 17 | */ 18 | 19 | import org.javaswift.joss.model.StoredObject; 20 | 21 | import fr.jeci.alfresco.ByteBufWritableByteChannel; 22 | import io.netty.buffer.ByteBuf; 23 | import io.netty.buffer.ByteBufInputStream; 24 | 25 | public class SwiftChannel extends ByteBufWritableByteChannel { 26 | 27 | private StoredObject storedObject; 28 | 29 | public SwiftChannel(StoredObject storedObject) { 30 | this.storedObject = storedObject; 31 | } 32 | 33 | @Override 34 | protected void implCloseChannel(ByteBuf buffer) { 35 | storedObject.uploadObject(new ByteBufInputStream(buffer)); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /alfresco-swift/src/main/java/fr/jeci/alfresco/swift/SwiftContentReader.java: -------------------------------------------------------------------------------- 1 | package fr.jeci.alfresco.swift; 2 | 3 | /* Copyright 2016, 2017 - Jeci SARL - http://jeci.fr 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public License 16 | along with this program. If not, see http://www.gnu.org/licenses/. 17 | */ 18 | 19 | import java.nio.channels.Channels; 20 | import java.nio.channels.ReadableByteChannel; 21 | 22 | import org.alfresco.repo.content.AbstractContentReader; 23 | import org.alfresco.service.cmr.repository.ContentIOException; 24 | import org.alfresco.service.cmr.repository.ContentReader; 25 | import org.javaswift.joss.model.StoredObject; 26 | 27 | public class SwiftContentReader extends AbstractContentReader implements ContentReader { 28 | 29 | private StoredObject storedObject; 30 | 31 | public SwiftContentReader(StoredObject object) { 32 | super(object.getName()); 33 | this.storedObject = object; 34 | } 35 | 36 | @Override 37 | protected ContentReader createReader() { 38 | return new SwiftContentReader(this.storedObject); 39 | } 40 | 41 | @Override 42 | protected ReadableByteChannel getDirectReadableChannel() { 43 | if (!exists()) { 44 | throw new ContentIOException("Content object does not exist on Swift"); 45 | } 46 | 47 | return Channels.newChannel(this.storedObject.downloadObjectAsInputStream()); 48 | } 49 | 50 | @Override 51 | public boolean exists() { 52 | return this.storedObject.exists(); 53 | } 54 | 55 | @Override 56 | public long getLastModified() { 57 | if (!exists()) { 58 | return 0L; 59 | } 60 | 61 | return this.storedObject.getLastModifiedAsDate().getTime(); 62 | } 63 | 64 | @Override 65 | public long getSize() { 66 | if (!exists()) { 67 | return 0L; 68 | } 69 | 70 | return this.storedObject.getContentLength(); 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /alfresco-swift/src/main/java/fr/jeci/alfresco/swift/SwiftContentWriter.java: -------------------------------------------------------------------------------- 1 | package fr.jeci.alfresco.swift; 2 | 3 | /* Copyright 2016, 2017 - Jeci SARL - http://jeci.fr 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public License 16 | along with this program. If not, see http://www.gnu.org/licenses/. 17 | */ 18 | 19 | import java.nio.channels.WritableByteChannel; 20 | 21 | import org.alfresco.repo.content.AbstractContentWriter; 22 | import org.alfresco.service.cmr.repository.ContentReader; 23 | import org.javaswift.joss.model.StoredObject; 24 | 25 | public class SwiftContentWriter extends AbstractContentWriter { 26 | private StoredObject storedObject; 27 | 28 | private final SwiftChannel channel; 29 | 30 | public SwiftContentWriter(StoredObject object) { 31 | super(object.getName(), null); 32 | this.storedObject = object; 33 | this.channel = new SwiftChannel(storedObject); 34 | 35 | } 36 | 37 | @Override 38 | protected ContentReader createReader() { 39 | return new SwiftContentReader(this.storedObject); 40 | } 41 | 42 | @Override 43 | protected WritableByteChannel getDirectWritableChannel() { 44 | return new SwiftChannel(storedObject); 45 | } 46 | 47 | @Override 48 | public long getSize() { 49 | return this.channel.getSize(); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /alfresco-swift/src/main/java/fr/jeci/alfresco/swift/SwiftServiceImpl.java: -------------------------------------------------------------------------------- 1 | package fr.jeci.alfresco.swift; 2 | 3 | /* Copyright 2016, 2017 - Jeci SARL - http://jeci.fr 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public License 16 | along with this program. If not, see http://www.gnu.org/licenses/. 17 | */ 18 | 19 | import java.io.IOException; 20 | 21 | import org.alfresco.service.cmr.repository.ContentReader; 22 | import org.alfresco.service.cmr.repository.ContentWriter; 23 | import org.apache.commons.lang3.StringUtils; 24 | import org.javaswift.joss.client.factory.AccountConfig; 25 | import org.javaswift.joss.client.factory.AccountFactory; 26 | import org.javaswift.joss.client.factory.AuthenticationMethod; 27 | import org.javaswift.joss.model.Account; 28 | import org.javaswift.joss.model.Container; 29 | import org.javaswift.joss.model.StoredObject; 30 | 31 | import fr.jeci.alfresco.ObjectStorageService; 32 | 33 | public class SwiftServiceImpl implements ObjectStorageService { 34 | 35 | private String username; 36 | private String password; 37 | private String url; 38 | private String tenantId; 39 | private String tenantName; 40 | private String containerName; 41 | private Container container; 42 | 43 | public void init() { 44 | 45 | AccountConfig config = new AccountConfig(); 46 | config.setAuthenticationMethod(AuthenticationMethod.BASIC); 47 | config.setUsername(username); 48 | config.setPassword(password); 49 | config.setAuthUrl(url); 50 | if (StringUtils.isNotEmpty(tenantId)) { 51 | config.setTenantId(tenantId); 52 | } 53 | if (StringUtils.isNotEmpty(tenantName)) { 54 | config.setTenantName(tenantName); 55 | } 56 | Account account = new AccountFactory(config).createAccount(); 57 | this.container = account.getContainer(containerName); 58 | } 59 | 60 | @Override 61 | public boolean isWriteSupported() { 62 | // this.container.getcontainerWritePermission() 63 | return true; 64 | } 65 | 66 | @Override 67 | public ContentReader getReader(String contentUrl) throws IOException { 68 | StoredObject object = this.container.getObject(contentUrl); 69 | return new SwiftContentReader(object); 70 | } 71 | 72 | @Override 73 | public ContentWriter getWriter(String contentUrl) throws IOException { 74 | StoredObject object = this.container.getObject(contentUrl); 75 | return new SwiftContentWriter(object); 76 | } 77 | 78 | @Override 79 | public boolean delete(String contentUrl) { 80 | StoredObject object = this.container.getObject(contentUrl); 81 | object.delete(); 82 | return true; 83 | } 84 | 85 | @Override 86 | public String getContainer() { 87 | return container.getName(); 88 | } 89 | 90 | public String getUsername() { 91 | return username; 92 | } 93 | 94 | public void setUsername(String username) { 95 | this.username = username; 96 | } 97 | 98 | public String getPassword() { 99 | return password; 100 | } 101 | 102 | public void setPassword(String password) { 103 | this.password = password; 104 | } 105 | 106 | public String getUrl() { 107 | return url; 108 | } 109 | 110 | public void setUrl(String url) { 111 | this.url = url; 112 | } 113 | 114 | public String getTenantId() { 115 | return tenantId; 116 | } 117 | 118 | public void setTenantId(String tenantId) { 119 | this.tenantId = tenantId; 120 | } 121 | 122 | public String getTenantName() { 123 | return tenantName; 124 | } 125 | 126 | public void setTenantName(String tenantName) { 127 | this.tenantName = tenantName; 128 | } 129 | 130 | public void setContainer(String containerName) { 131 | this.containerName = containerName; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | fr.jeci.alfresco-object-storage 6 | 1.0.0 7 | alfresco-object-storage-parent 8 | pom 9 | Object Storage Connectors for Alfresco 10 | Object Storage Connectors (Swift, Red Hat Ceph, OpenIO) for Alfresco 11 | 12 | http://jeci.fr/ 13 | 14 | 15 | alfresco-object-storage-commons 16 | alfresco-ceph-rados 17 | alfresco-openio 18 | alfresco-swift 19 | 20 | 21 | 22 | org.alfresco.maven 23 | alfresco-sdk-parent 24 | 2.2.0 25 | 26 | 27 | 28 | 29 | GNU Lesser General Public License v3.0 or later 30 | http://www.gnu.org/licenses/lgpl-3.0-standalone.html 31 | 32 | 33 | 34 | 35 | 36 | 37 | 5.2.f 38 | 1.8 39 | 40 | 41 | 42 | 43 | 44 | jeremie.lesage 45 | Jeremie Lesage 46 | jeremie.lesage@jeci.fr 47 | https://jeci.fr/ 48 | Jeci 49 | https://jeci.fr/ 50 | +1 51 | 52 | 53 | 54 | 55 | 56 | Florent Manens 57 | 58 | 59 | Beezim 60 | http://www.beezim.fr/ 61 | +1 62 | 63 | 64 | 65 | 66 | 67 | 70 | 71 | ${alfresco.groupId} 72 | alfresco-platform-distribution 73 | ${alfresco.version} 74 | pom 75 | import 76 | 77 | 78 | 79 | 80 | 81 | 82 | enterprise 83 | 84 | 85 | ${alfresco.groupId} 86 | alfresco-enterprise-repository 87 | ${alfresco.version} 88 | provided 89 | 90 | 91 | 92 | 93 | 94 | --------------------------------------------------------------------------------