diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..dce454f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,129 @@
+# Created by https://www.gitignore.io
+
+### Java ###
+*.class
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.ear
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+
+### Maven ###
+target/
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+pom.xml.next
+release.properties
+dependency-reduced-pom.xml
+buildNumber.properties
+
+
+### Eclipse ###
+*.pydevproject
+.metadata
+.gradle
+bin/
+tmp/
+*.tmp
+*.bak
+*.swp
+*~.nib
+local.properties
+.settings/
+.loadpath
+
+# Eclipse Core
+.project
+
+# External tool builders
+.externalToolBuilders/
+
+# Locally stored "Eclipse launch configurations"
+*.launch
+
+# CDT-specific
+.cproject
+
+# JDT-specific (Eclipse Java Development Tools)
+.classpath
+
+# PDT-specific
+.buildpath
+
+# sbteclipse plugin
+.target
+
+# TeXlipse plugin
+.texlipse
+
+
+### Intellij ###
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm
+
+*.iml
+
+## Directory-based project format:
+.idea/
+# if you remove the above rule, at least ignore the following:
+
+# User-specific stuff:
+# .idea/workspace.xml
+# .idea/tasks.xml
+# .idea/dictionaries
+
+# Sensitive or high-churn files:
+# .idea/dataSources.ids
+# .idea/dataSources.xml
+# .idea/sqlDataSources.xml
+# .idea/dynamic.xml
+# .idea/uiDesigner.xml
+
+# Gradle:
+# .idea/gradle.xml
+# .idea/libraries
+
+# Mongo Explorer plugin:
+# .idea/mongoSettings.xml
+
+## File-based project format:
+*.ipr
+*.iws
+
+## Plugin-specific files:
+
+# IntelliJ
+/out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+
+
+### NetBeans ###
+nbproject/private/
+build/
+nbbuild/
+dist/
+nbdist/
+nbactions.xml
+nb-configuration.xml
+.nb-gradle/
+
+confluence-plugin/src/main/typescript/tmp
+confluence-plugin/src/main/typescript/node_modules
+
diff --git a/LICENCE.md b/LICENCE.md
new file mode 100644
index 0000000..4057574
--- /dev/null
+++ b/LICENCE.md
@@ -0,0 +1,195 @@
+Apache License
+==============
+
+_Version 2.0, January 2004_
+_<>_
+
+### Terms and Conditions for use, reproduction, and distribution
+
+#### 1. Definitions
+
+“License” shall mean the terms and conditions for use, reproduction, and
+distribution as defined by Sections 1 through 9 of this document.
+
+“Licensor” shall mean the copyright owner or entity authorized by the copyright
+owner that is granting the License.
+
+“Legal Entity” shall mean the union of the acting entity and all other entities
+that control, are controlled by, or are under common control with that entity.
+For the purposes of this definition, “control” means **(i)** the power, direct or
+indirect, to cause the direction or management of such entity, whether by
+contract or otherwise, or **(ii)** ownership of fifty percent (50%) or more of the
+outstanding shares, or **(iii)** beneficial ownership of such entity.
+
+“You” (or “Your”) shall mean an individual or Legal Entity exercising
+permissions granted by this License.
+
+“Source” form shall mean the preferred form for making modifications, including
+but not limited to software source code, documentation source, and configuration
+files.
+
+“Object” form shall mean any form resulting from mechanical transformation or
+translation of a Source form, including but not limited to compiled object code,
+generated documentation, and conversions to other media types.
+
+“Work” shall mean the work of authorship, whether in Source or Object form, made
+available under the License, as indicated by a copyright notice that is included
+in or attached to the work (an example is provided in the Appendix below).
+
+“Derivative Works” shall mean any work, whether in Source or Object form, that
+is based on (or derived from) the Work and for which the editorial revisions,
+annotations, elaborations, or other modifications represent, as a whole, an
+original work of authorship. For the purposes of this License, Derivative Works
+shall not include works that remain separable from, or merely link (or bind by
+name) to the interfaces of, the Work and Derivative Works thereof.
+
+“Contribution” shall mean any work of authorship, including the original version
+of the Work and any modifications or additions to that Work or Derivative Works
+thereof, that is intentionally submitted to Licensor for inclusion in the Work
+by the copyright owner or by an individual or Legal Entity authorized to submit
+on behalf of the copyright owner. For the purposes of this definition,
+“submitted” means any form of electronic, verbal, or written communication sent
+to the Licensor or its representatives, including but not limited to
+communication on electronic mailing lists, source code control systems, and
+issue tracking systems that are managed by, or on behalf of, the Licensor for
+the purpose of discussing and improving the Work, but excluding communication
+that is conspicuously marked or otherwise designated in writing by the copyright
+owner as “Not a Contribution.”
+
+“Contributor” shall mean Licensor and any individual or Legal Entity on behalf
+of whom a Contribution has been received by Licensor and subsequently
+incorporated within the Work.
+
+#### 2. Grant of Copyright License
+
+Subject to the terms and conditions of this License, each Contributor hereby
+grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
+irrevocable copyright license to reproduce, prepare Derivative Works of,
+publicly display, publicly perform, sublicense, and distribute the Work and such
+Derivative Works in Source or Object form.
+
+#### 3. Grant of Patent License
+
+Subject to the terms and conditions of this License, each Contributor hereby
+grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
+irrevocable (except as stated in this section) patent license to make, have
+made, use, offer to sell, sell, import, and otherwise transfer the Work, where
+such license applies only to those patent claims licensable by such Contributor
+that are necessarily infringed by their Contribution(s) alone or by combination
+of their Contribution(s) with the Work to which such Contribution(s) was
+submitted. If You institute patent litigation against any entity (including a
+cross-claim or counterclaim in a lawsuit) alleging that the Work or a
+Contribution incorporated within the Work constitutes direct or contributory
+patent infringement, then any patent licenses granted to You under this License
+for that Work shall terminate as of the date such litigation is filed.
+
+#### 4. Redistribution
+
+You may reproduce and distribute copies of the Work or Derivative Works thereof
+in any medium, with or without modifications, and in Source or Object form,
+provided that You meet the following conditions:
+
+* **(a)** You must give any other recipients of the Work or Derivative Works a copy of
+this License; and
+* **(b)** You must cause any modified files to carry prominent notices stating that You
+changed the files; and
+* **(c)** You must retain, in the Source form of any Derivative Works that You distribute,
+all copyright, patent, trademark, and attribution notices from the Source form
+of the Work, excluding those notices that do not pertain to any part of the
+Derivative Works; and
+* **(d)** If the Work includes a “NOTICE” text file as part of its distribution, then any
+Derivative Works that You distribute must include a readable copy of the
+attribution notices contained within such NOTICE file, excluding those notices
+that do not pertain to any part of the Derivative Works, in at least one of the
+following places: within a NOTICE text file distributed as part of the
+Derivative Works; within the Source form or documentation, if provided along
+with the Derivative Works; or, within a display generated by the Derivative
+Works, if and wherever such third-party notices normally appear. The contents of
+the NOTICE file are for informational purposes only and do not modify the
+License. You may add Your own attribution notices within Derivative Works that
+You distribute, alongside or as an addendum to the NOTICE text from the Work,
+provided that such additional attribution notices cannot be construed as
+modifying the License.
+
+You may add Your own copyright statement to Your modifications and may provide
+additional or different license terms and conditions for use, reproduction, or
+distribution of Your modifications, or for any such Derivative Works as a whole,
+provided Your use, reproduction, and distribution of the Work otherwise complies
+with the conditions stated in this License.
+
+#### 5. Submission of Contributions
+
+Unless You explicitly state otherwise, any Contribution intentionally submitted
+for inclusion in the Work by You to the Licensor shall be under the terms and
+conditions of this License, without any additional terms or conditions.
+Notwithstanding the above, nothing herein shall supersede or modify the terms of
+any separate license agreement you may have executed with Licensor regarding
+such Contributions.
+
+#### 6. Trademarks
+
+This License does not grant permission to use the trade names, trademarks,
+service marks, or product names of the Licensor, except as required for
+reasonable and customary use in describing the origin of the Work and
+reproducing the content of the NOTICE file.
+
+#### 7. Disclaimer of Warranty
+
+Unless required by applicable law or agreed to in writing, Licensor provides the
+Work (and each Contributor provides its Contributions) on an “AS IS” BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+including, without limitation, any warranties or conditions of TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
+solely responsible for determining the appropriateness of using or
+redistributing the Work and assume any risks associated with Your exercise of
+permissions under this License.
+
+#### 8. Limitation of Liability
+
+In no event and under no legal theory, whether in tort (including negligence),
+contract, or otherwise, unless required by applicable law (such as deliberate
+and grossly negligent acts) or agreed to in writing, shall any Contributor be
+liable to You for damages, including any direct, indirect, special, incidental,
+or consequential damages of any character arising as a result of this License or
+out of the use or inability to use the Work (including but not limited to
+damages for loss of goodwill, work stoppage, computer failure or malfunction, or
+any and all other commercial damages or losses), even if such Contributor has
+been advised of the possibility of such damages.
+
+#### 9. Accepting Warranty or Additional Liability
+
+While redistributing the Work or Derivative Works thereof, You may choose to
+offer, and charge a fee for, acceptance of support, warranty, indemnity, or
+other liability obligations and/or rights consistent with this License. However,
+in accepting such obligations, You may act only on Your own behalf and on Your
+sole responsibility, not on behalf of any other Contributor, and only if You
+agree to indemnify, defend, and hold each Contributor harmless for any liability
+incurred by, or claims asserted against, such Contributor by reason of your
+accepting any such warranty or additional liability.
+
+_END OF TERMS AND CONDITIONS_
+
+### APPENDIX: How to apply the Apache License to your work
+
+To apply the Apache License to your work, attach the following boilerplate
+notice, with the fields enclosed by brackets `[]` replaced with your own
+identifying information. (Don't include the brackets!) The text should be
+enclosed in the appropriate comment syntax for the file format. We also
+recommend that a file or class name and description of purpose be included on
+the same “printed page” as the copyright notice for easier identification within
+third-party archives.
+
+ Copyright (c) 2016 NetworkedAssets Sp. z o.o. (http://networkedassets.com)
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d56d4e9
--- /dev/null
+++ b/README.md
@@ -0,0 +1,38 @@
+# ![](https://raw.githubusercontent.com/NetworkedAssets/autodoc/master/transformer/src/main/resources/images/transformer_logo.png "Transformer")
+
+Java application used by [NetworkedAssets's](http://www.networkedassets.com/) [Documentation from Code Plugin](http://condoc.networkedassets.com/) for Atlassian Confluence.
+
+## Installation
+
+1. Make sure you've got **JDK 8** installed on your server, your **JAVA_HOME** and **PATH** environment variables are properly set.
+
+```bash
+# javac -version
+# echo $JAVA_HOME
+```
+
+2. Prepare your favourite SSH and SFTP clients.
+3. Copy the transformer jar and transformer helper scripts to your server via sftp. Suggested location is */opt/autodoc*.
+4. Connect via **SSH** to your server.
+
+```
+ssh root@example
+```
+
+5. On your server machine run **transformer-start.sh** contained in *scripts/server*.
+
+```bash
+# /opt/autodoc/transformer-start.sh
+```
+
+## Default Settings
+
+By default properties look like this:
+
+```
+jetty.port=8050
+jetty.address=http://localhost/
+jetty.port=
+```
+
+You can change them by creating **transformer.properties** file next to the **transformer.jar** and add properties you want to override.
\ No newline at end of file
diff --git a/confluence-plugin/LICENCE.md b/confluence-plugin/LICENCE.md
new file mode 100644
index 0000000..4057574
--- /dev/null
+++ b/confluence-plugin/LICENCE.md
@@ -0,0 +1,195 @@
+Apache License
+==============
+
+_Version 2.0, January 2004_
+_<>_
+
+### Terms and Conditions for use, reproduction, and distribution
+
+#### 1. Definitions
+
+“License” shall mean the terms and conditions for use, reproduction, and
+distribution as defined by Sections 1 through 9 of this document.
+
+“Licensor” shall mean the copyright owner or entity authorized by the copyright
+owner that is granting the License.
+
+“Legal Entity” shall mean the union of the acting entity and all other entities
+that control, are controlled by, or are under common control with that entity.
+For the purposes of this definition, “control” means **(i)** the power, direct or
+indirect, to cause the direction or management of such entity, whether by
+contract or otherwise, or **(ii)** ownership of fifty percent (50%) or more of the
+outstanding shares, or **(iii)** beneficial ownership of such entity.
+
+“You” (or “Your”) shall mean an individual or Legal Entity exercising
+permissions granted by this License.
+
+“Source” form shall mean the preferred form for making modifications, including
+but not limited to software source code, documentation source, and configuration
+files.
+
+“Object” form shall mean any form resulting from mechanical transformation or
+translation of a Source form, including but not limited to compiled object code,
+generated documentation, and conversions to other media types.
+
+“Work” shall mean the work of authorship, whether in Source or Object form, made
+available under the License, as indicated by a copyright notice that is included
+in or attached to the work (an example is provided in the Appendix below).
+
+“Derivative Works” shall mean any work, whether in Source or Object form, that
+is based on (or derived from) the Work and for which the editorial revisions,
+annotations, elaborations, or other modifications represent, as a whole, an
+original work of authorship. For the purposes of this License, Derivative Works
+shall not include works that remain separable from, or merely link (or bind by
+name) to the interfaces of, the Work and Derivative Works thereof.
+
+“Contribution” shall mean any work of authorship, including the original version
+of the Work and any modifications or additions to that Work or Derivative Works
+thereof, that is intentionally submitted to Licensor for inclusion in the Work
+by the copyright owner or by an individual or Legal Entity authorized to submit
+on behalf of the copyright owner. For the purposes of this definition,
+“submitted” means any form of electronic, verbal, or written communication sent
+to the Licensor or its representatives, including but not limited to
+communication on electronic mailing lists, source code control systems, and
+issue tracking systems that are managed by, or on behalf of, the Licensor for
+the purpose of discussing and improving the Work, but excluding communication
+that is conspicuously marked or otherwise designated in writing by the copyright
+owner as “Not a Contribution.”
+
+“Contributor” shall mean Licensor and any individual or Legal Entity on behalf
+of whom a Contribution has been received by Licensor and subsequently
+incorporated within the Work.
+
+#### 2. Grant of Copyright License
+
+Subject to the terms and conditions of this License, each Contributor hereby
+grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
+irrevocable copyright license to reproduce, prepare Derivative Works of,
+publicly display, publicly perform, sublicense, and distribute the Work and such
+Derivative Works in Source or Object form.
+
+#### 3. Grant of Patent License
+
+Subject to the terms and conditions of this License, each Contributor hereby
+grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
+irrevocable (except as stated in this section) patent license to make, have
+made, use, offer to sell, sell, import, and otherwise transfer the Work, where
+such license applies only to those patent claims licensable by such Contributor
+that are necessarily infringed by their Contribution(s) alone or by combination
+of their Contribution(s) with the Work to which such Contribution(s) was
+submitted. If You institute patent litigation against any entity (including a
+cross-claim or counterclaim in a lawsuit) alleging that the Work or a
+Contribution incorporated within the Work constitutes direct or contributory
+patent infringement, then any patent licenses granted to You under this License
+for that Work shall terminate as of the date such litigation is filed.
+
+#### 4. Redistribution
+
+You may reproduce and distribute copies of the Work or Derivative Works thereof
+in any medium, with or without modifications, and in Source or Object form,
+provided that You meet the following conditions:
+
+* **(a)** You must give any other recipients of the Work or Derivative Works a copy of
+this License; and
+* **(b)** You must cause any modified files to carry prominent notices stating that You
+changed the files; and
+* **(c)** You must retain, in the Source form of any Derivative Works that You distribute,
+all copyright, patent, trademark, and attribution notices from the Source form
+of the Work, excluding those notices that do not pertain to any part of the
+Derivative Works; and
+* **(d)** If the Work includes a “NOTICE” text file as part of its distribution, then any
+Derivative Works that You distribute must include a readable copy of the
+attribution notices contained within such NOTICE file, excluding those notices
+that do not pertain to any part of the Derivative Works, in at least one of the
+following places: within a NOTICE text file distributed as part of the
+Derivative Works; within the Source form or documentation, if provided along
+with the Derivative Works; or, within a display generated by the Derivative
+Works, if and wherever such third-party notices normally appear. The contents of
+the NOTICE file are for informational purposes only and do not modify the
+License. You may add Your own attribution notices within Derivative Works that
+You distribute, alongside or as an addendum to the NOTICE text from the Work,
+provided that such additional attribution notices cannot be construed as
+modifying the License.
+
+You may add Your own copyright statement to Your modifications and may provide
+additional or different license terms and conditions for use, reproduction, or
+distribution of Your modifications, or for any such Derivative Works as a whole,
+provided Your use, reproduction, and distribution of the Work otherwise complies
+with the conditions stated in this License.
+
+#### 5. Submission of Contributions
+
+Unless You explicitly state otherwise, any Contribution intentionally submitted
+for inclusion in the Work by You to the Licensor shall be under the terms and
+conditions of this License, without any additional terms or conditions.
+Notwithstanding the above, nothing herein shall supersede or modify the terms of
+any separate license agreement you may have executed with Licensor regarding
+such Contributions.
+
+#### 6. Trademarks
+
+This License does not grant permission to use the trade names, trademarks,
+service marks, or product names of the Licensor, except as required for
+reasonable and customary use in describing the origin of the Work and
+reproducing the content of the NOTICE file.
+
+#### 7. Disclaimer of Warranty
+
+Unless required by applicable law or agreed to in writing, Licensor provides the
+Work (and each Contributor provides its Contributions) on an “AS IS” BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+including, without limitation, any warranties or conditions of TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
+solely responsible for determining the appropriateness of using or
+redistributing the Work and assume any risks associated with Your exercise of
+permissions under this License.
+
+#### 8. Limitation of Liability
+
+In no event and under no legal theory, whether in tort (including negligence),
+contract, or otherwise, unless required by applicable law (such as deliberate
+and grossly negligent acts) or agreed to in writing, shall any Contributor be
+liable to You for damages, including any direct, indirect, special, incidental,
+or consequential damages of any character arising as a result of this License or
+out of the use or inability to use the Work (including but not limited to
+damages for loss of goodwill, work stoppage, computer failure or malfunction, or
+any and all other commercial damages or losses), even if such Contributor has
+been advised of the possibility of such damages.
+
+#### 9. Accepting Warranty or Additional Liability
+
+While redistributing the Work or Derivative Works thereof, You may choose to
+offer, and charge a fee for, acceptance of support, warranty, indemnity, or
+other liability obligations and/or rights consistent with this License. However,
+in accepting such obligations, You may act only on Your own behalf and on Your
+sole responsibility, not on behalf of any other Contributor, and only if You
+agree to indemnify, defend, and hold each Contributor harmless for any liability
+incurred by, or claims asserted against, such Contributor by reason of your
+accepting any such warranty or additional liability.
+
+_END OF TERMS AND CONDITIONS_
+
+### APPENDIX: How to apply the Apache License to your work
+
+To apply the Apache License to your work, attach the following boilerplate
+notice, with the fields enclosed by brackets `[]` replaced with your own
+identifying information. (Don't include the brackets!) The text should be
+enclosed in the appropriate comment syntax for the file format. We also
+recommend that a file or class name and description of purpose be included on
+the same “printed page” as the copyright notice for easier identification within
+third-party archives.
+
+ Copyright (c) 2016 NetworkedAssets Sp. z o.o. (http://networkedassets.com)
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
diff --git a/confluence-plugin/README.md b/confluence-plugin/README.md
new file mode 100644
index 0000000..e6604e8
--- /dev/null
+++ b/confluence-plugin/README.md
@@ -0,0 +1,13 @@
+#
+
+Plugin for Confluence - Team Collaboration Software from Atlassian created by [NetworkedAssets](http://www.networkedassets.com/). For more detailed information, please have a look onto [Documentation from Code Plugin](http://condoc.networkedassets.com/).
+
+## Installation
+
+1. Log in to Confluence as administrator.
+2. Install [DoC Plugin](http://www.google.com) via Atlassian Marketplace.
+3. Log in to Stash and/or Bitbucket.
+4. Install [Event Listener for Stash](http://www.google.com) and/or [Event Listener for Bitbucket](http://www.google.com) via Atlassian Marketplace.
+5. Download [The Transformer java project](https://github.com/networkedassets/transformer).
+6. Get your Transformer up and running following [our guide](https://github.com/networkedassets/transformer/README.md).
+
diff --git a/confluence-plugin/pom.xml b/confluence-plugin/pom.xml
new file mode 100644
index 0000000..725fcee
--- /dev/null
+++ b/confluence-plugin/pom.xml
@@ -0,0 +1,208 @@
+
+
+
+ 4.0.0
+ confluence-plugin
+ 0.4.5
+
+ com.networkedassets.autodoc
+ autodoc-parent
+ 0.4.5
+
+
+ NetworkedAssets Sp. z o.o
+ http://www.networkedassets.com/en/
+
+ DoC
+ DoC macro displaying documentation in various forms on pages
+ atlassian-plugin
+
+
+
+ junit
+ junit
+ 4.12
+
+
+ com.atlassian.confluence
+ confluence
+ ${confluence.version}
+ provided
+
+
+ com.atlassian.activeobjects
+ activeobjects-plugin
+ 1.1.3
+ provided
+
+
+ com.networkedassets.autodoc
+ functional-utils
+ 0.4.5
+
+
+ com.mashape.unirest
+ unirest-java
+ 1.4.7
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.8.1
+
+
+
+
+ com.atlassian.plugins
+ atlassian-plugins-osgi-testrunner
+ ${plugin.testrunner.version}
+ test
+
+
+ javax.ws.rs
+ jsr311-api
+ 1.1.1
+ provided
+
+
+ javax.servlet
+ servlet-api
+ 2.4
+ provided
+
+
+ org.slf4j
+ slf4j-api
+ 1.6.6
+ provided
+
+
+
+
+ com.atlassian.upm
+ licensing-api
+ 2.18.5
+ provided
+
+
+ com.atlassian.upm
+ upm-api
+ 2.18.5
+ provided
+
+
+
+
+
+
+
+ com.atlassian.maven.plugins
+ maven-confluence-plugin
+ ${amps.version}
+ true
+
+ ${confluence.version}
+ ${confluence.data.version}
+ false
+
+
+
+ maven-compiler-plugin
+
+
+ 1.8
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.19
+
+
+ **/*IntegrationTest.java
+
+
+
+
+ org.apache.maven.surefire
+ surefire-junit47
+ 2.19
+
+
+
+
+
+ com.github.eirslett
+ frontend-maven-plugin
+ 1.0
+
+
+ src/main/typescript
+ target
+
+
+
+
+ install node and npm
+
+ install-node-and-npm
+
+
+ v6.2.2
+ 3.9.5
+
+
+
+
+ npm install
+
+ npm
+
+
+
+ install
+
+
+
+
+ npm build
+
+ npm
+
+ compile
+
+
+ run prod
+
+
+
+
+
+
+
+
+
+
+ atlassian-public2
+ https://maven.atlassian.com/content/repositories/atlassian-public
+
+ true
+ never
+ warn
+
+
+ true
+ warn
+
+
+
+
+
+ 5.8.6
+ 5.8.6
+ 5.0.13
+ 1.2.3
+
+
diff --git a/confluence-plugin/src/main/java/com/networkedassets/autodoc/DocMacro.java b/confluence-plugin/src/main/java/com/networkedassets/autodoc/DocMacro.java
new file mode 100644
index 0000000..5b908bf
--- /dev/null
+++ b/confluence-plugin/src/main/java/com/networkedassets/autodoc/DocMacro.java
@@ -0,0 +1,60 @@
+package com.networkedassets.autodoc;
+
+import com.atlassian.confluence.content.render.xhtml.ConversionContext;
+import com.atlassian.confluence.macro.Macro;
+import com.atlassian.confluence.macro.MacroExecutionException;
+import com.atlassian.confluence.renderer.radeox.macros.MacroUtils;
+import com.atlassian.confluence.util.velocity.VelocityUtils;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.commons.io.IOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public class DocMacro implements Macro {
+ private Logger log = LoggerFactory.getLogger(DocMacro.class);
+
+ @Override
+ public String execute(Map params, String s, ConversionContext conversionContext) throws MacroExecutionException {
+ String macroSection;
+ String resourcesPath = "download/resources/com.networkedassets.autodoc.confluence-plugin:macro-resources/macroResources/";
+
+ try {
+ macroSection = IOUtils.toString(this.getClass().getClassLoader().getResourceAsStream("/frontend/index.html"));
+ } catch (IOException e) {
+ throw new MacroExecutionException(e);
+ }
+
+ macroSection = ("")[0] + "section>";
+
+ Map context = MacroUtils.defaultVelocityContext();
+
+ context.put("macroSectionHtml", macroSection);
+ context.put("resourcesPath", resourcesPath);
+
+ String paramsString = params.entrySet().stream().map(e -> e.getKey() + ": " + e.getValue()).collect(Collectors.joining());
+ log.warn(paramsString);
+
+ try {
+ context.put("paramsJson", new ObjectMapper().writeValueAsString(params));
+ } catch(JsonProcessingException e) {
+ e.printStackTrace();
+ }
+
+ return VelocityUtils.getRenderedTemplate("/macro.vm", context);
+ }
+
+ @Override
+ public BodyType getBodyType() {
+ return BodyType.NONE;
+ }
+
+ @Override
+ public OutputType getOutputType() {
+ return OutputType.BLOCK;
+ }
+}
diff --git a/confluence-plugin/src/main/java/com/networkedassets/autodoc/FrontendResourcesAccessorService.java b/confluence-plugin/src/main/java/com/networkedassets/autodoc/FrontendResourcesAccessorService.java
new file mode 100644
index 0000000..1ff19b4
--- /dev/null
+++ b/confluence-plugin/src/main/java/com/networkedassets/autodoc/FrontendResourcesAccessorService.java
@@ -0,0 +1,65 @@
+package com.networkedassets.autodoc;
+
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.io.IOUtils;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.StreamingOutput;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+@Path("frontend")
+public class FrontendResourcesAccessorService {
+
+ @GET
+ @Path("{path:.*}")
+ public Response getResource(@Context final HttpServletRequest req) {
+ StreamingOutput so = new StreamingOutput() {
+ @Override
+ public void write(OutputStream output) throws IOException, WebApplicationException {
+ InputStream res = this.getClass().getClassLoader().getResourceAsStream(req.getPathInfo());
+ IOUtils.copy(res, output);
+ output.flush();
+ }
+ };
+
+ return Response.ok(so).header("Content-Type", inferContentType(req.getPathInfo())).build();
+ }
+
+ private String inferContentType(String path) {
+ try {
+ String type = Files.probeContentType(Paths.get(path));
+ if (type == null) {
+ String extension = FilenameUtils.getExtension(path);
+ switch (extension) {
+ case "js":
+ return "application/javascript";
+ case "css":
+ return "text/css";
+ case "ico":
+ return "image/x-icon";
+ case "json":
+ return "application/json";
+ case "png":
+ return "image/png";
+ case "gif":
+ return "image/gif";
+ case "jpg":
+ case "jpeg":
+ return "image/jpeg";
+ }
+ }
+ return type;
+ } catch (IOException e) {
+ return "text/plain";
+ }
+ }
+}
diff --git a/confluence-plugin/src/main/java/com/networkedassets/autodoc/TransformerClient.java b/confluence-plugin/src/main/java/com/networkedassets/autodoc/TransformerClient.java
new file mode 100644
index 0000000..097cecb
--- /dev/null
+++ b/confluence-plugin/src/main/java/com/networkedassets/autodoc/TransformerClient.java
@@ -0,0 +1,223 @@
+package com.networkedassets.autodoc;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.mashape.unirest.http.ObjectMapper;
+import com.mashape.unirest.http.Unirest;
+import com.mashape.unirest.http.exceptions.UnirestException;
+import com.networkedassets.autodoc.configuration.BundleAccessTokenService;
+import com.networkedassets.autodoc.configuration.DocSettingsService;
+import com.networkedassets.autodoc.configuration.TokenNotFoundException;
+import com.networkedassets.autodoc.documentation.Documentation;
+import com.networkedassets.autodoc.documentation.DocumentationPiece;
+import com.networkedassets.autodoc.documentation.transformer2.Bundle;
+import com.networkedassets.autodoc.documentation.transformer2.DocItem;
+import com.networkedassets.autodoc.documentation.transformer2.DocItemSet;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
+import org.apache.http.conn.ssl.SSLContextBuilder;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+import static com.networkedassets.autodoc.documentation.transformer2.DocItemSet.JAVADOC_TYPE;
+import static com.networkedassets.autodoc.documentation.transformer2.DocItemSet.UML_TYPE;
+
+public class TransformerClient {
+ private static final String BUNDLES = "/rest/bundles";
+ private static final int CONNECTION_TIMEOUT = 90000;
+ private static final int SOCKET_TIMEOUT = 90000;
+ private static final com.fasterxml.jackson.databind.ObjectMapper OBJECT_MAPPER = new com.fasterxml.jackson.databind.ObjectMapper();
+
+ public static final Logger log = LoggerFactory.getLogger(TransformerClient.class);
+
+ private DocSettingsService docSettingsService;
+ private BundleAccessTokenService bundleAccessTokenService;
+
+ public TransformerClient(DocSettingsService docSettingsService, BundleAccessTokenService bundleAccessTokenService) {
+ this.docSettingsService = docSettingsService;
+ this.bundleAccessTokenService = bundleAccessTokenService;
+ log.debug("Transformer server constructing");
+ Unirest.setObjectMapper(getConfiguredObjectMapper());
+ Unirest.setHttpClient(getConfiguredHttpClient());
+ }
+
+ public String getUrl() {
+ return docSettingsService.getTransformerUrl();
+ }
+
+ private static CloseableHttpClient getConfiguredHttpClient() {
+ try {
+
+ return HttpClients.custom()
+ .setDefaultRequestConfig(RequestConfig.custom().setSocketTimeout(SOCKET_TIMEOUT)
+ .setConnectTimeout(CONNECTION_TIMEOUT).build())
+ .setHostnameVerifier(new AllowAllHostnameVerifier())
+ .setSslcontext(new SSLContextBuilder().loadTrustMaterial(null, (_1, _2) -> true).build()).build();
+ } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static ObjectMapper getConfiguredObjectMapper() {
+ return new ObjectMapper() {
+ private com.fasterxml.jackson.databind.ObjectMapper jacksonObjectMapper = new com.fasterxml.jackson.databind.ObjectMapper();
+
+ @Override
+ public T readValue(String value, Class valueType) {
+ try {
+ return jacksonObjectMapper.readValue(value, valueType);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public String writeValue(Object value) {
+ try {
+ return jacksonObjectMapper.writeValueAsString(value);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ };
+ }
+
+ public Optional getBundleById(String macroOwnerKey, int bundleId) throws UnirestException {
+ String token = null;
+ try {
+ token = bundleAccessTokenService.getForUserKey(macroOwnerKey);
+ } catch (TokenNotFoundException e) {
+ return Optional.empty();
+ }
+ JSONArray array = Unirest
+ .get(getUrl() + BUNDLES)
+ .header("Authorization", "Bearer " + token)
+ .asJson()
+ .getBody()
+ .getArray();
+ for (int i = 0; i < array.length(); i++) {
+ JSONObject jsonObject = array.getJSONObject(i);
+ if (jsonObject.getInt("id") == bundleId)
+ return Optional.of(new Bundle(jsonObject.getInt("id"), jsonObject.getString("name")));
+ }
+ return Optional.empty();
+ }
+
+ public List getAllBundles(String macroOwnerKey) throws UnirestException {
+ List res = new ArrayList<>();
+ String token = null;
+ try {
+ token = bundleAccessTokenService.getForUserKey(macroOwnerKey);
+ } catch (TokenNotFoundException e) {
+ throw new UnirestException(e);
+ }
+ JSONArray array = Unirest
+ .get(getUrl() + BUNDLES)
+ .header("Authorization", "Bearer " + token)
+ .asJson()
+ .getBody()
+ .getArray();
+ for (int i = 0; i < array.length(); i++) {
+ JSONObject jsonObject = array.getJSONObject(i);
+ res.add(new Bundle(jsonObject.getInt("id"), jsonObject.getString("name")));
+ }
+ return res;
+ }
+
+ public Optional getDocumentation(String macroOwnerKey, Bundle bundle, String documentationType) throws UnirestException {
+ final String token;
+ try {
+ token = bundleAccessTokenService.getForUserKey(macroOwnerKey);
+ } catch (TokenNotFoundException e) {
+ return Optional.empty();
+ }
+ List docItemSetList = getDocItemSets(token, bundle);
+ String type = documentationType.equals("uml") ? UML_TYPE : JAVADOC_TYPE;
+ return docItemSetList.stream().filter(docItemSet -> docItemSet.getType().equals(type)).findAny()
+ .flatMap(docItemSet -> {
+ try {
+ JSONObject docItemSetJson = Unirest
+ .get(getUrl() + "/rest/docitemsets/{id}")
+ .routeParam("id", String.valueOf(docItemSet.getId()))
+ .header("Authorization", "Bearer " + token)
+ .asJson()
+ .getBody()
+ .getObject();
+ JSONArray docItems = docItemSetJson.getJSONArray("docItems");
+ JSONObject docItem = docItems.getJSONObject(0);
+ String content = docItem.getString("content");
+ JsonNode jsonNode = OBJECT_MAPPER.readTree(content);
+ JsonNode pieces = jsonNode.get("pieces");
+ Documentation doc = new Documentation();
+ doc.setDocumentationType(documentationType);
+ doc.setBundle(bundle.getName());
+ List docPieces = new ArrayList<>();
+ for (JsonNode piece: pieces) {
+ DocumentationPiece documentationPiece = new DocumentationPiece();
+ documentationPiece.setDocumentation(doc);
+ documentationPiece.setPieceName(piece.get("pieceName").asText());
+ documentationPiece.setPieceType(piece.get("pieceType").asText());
+ documentationPiece.setContent(piece.get("content").asText());
+ docPieces.add(documentationPiece);
+ }
+ doc.setDocumentationPieces(docPieces);
+ return Optional.of(doc);
+ } catch (UnirestException | IOException e) {
+ e.printStackTrace();
+ return Optional.empty();
+ }
+ });
+ }
+
+ private List getDocItemSets(String token, Bundle bundle) throws UnirestException {
+ JSONObject bundleJson = Unirest
+ .get(getUrl() + "/rest/bundles/{id}")
+ .routeParam("id", Integer.toString(bundle.getId()))
+ .header("Authorization", "Bearer " + token)
+ .asJson()
+ .getBody()
+ .getObject();
+ JSONArray sourceUnits = bundleJson.getJSONArray("sourceUnits");
+ List res = new ArrayList<>();
+ for (int i = 0; i < sourceUnits.length(); i++) {
+ JSONArray docItemSets = sourceUnits.getJSONObject(i).getJSONArray("docItemSets");
+ for (int j = 0; j < docItemSets.length(); j++) {
+ JSONObject docItemSet = docItemSets.getJSONObject(j);
+ List docItems = getDocItems(docItemSet);
+ res.add(new DocItemSet(docItemSet.getString("type"), docItems, docItemSet.getInt("id")));
+ }
+ }
+ return res;
+ }
+
+ private List getDocItems(JSONObject docItemSet) {
+ ArrayList res = new ArrayList<>();
+ JSONArray docItems = docItemSet.getJSONArray("docItems");
+ for (int i = 0; i < docItems.length(); i++) {
+ JSONObject docItem = docItems.getJSONObject(i);
+ res.add(new DocItem(docItem.getInt("id")));
+ }
+ return res;
+ }
+
+ public String getToken(BundleAccessTokenService.Credentials credentials) throws UnirestException {
+ return Unirest.put(getUrl() + "/rest/users/signIn")
+ .header("Content-Type", "application/json")
+ .body(credentials)
+ .asJson()
+ .getBody()
+ .getObject()
+ .getString("token");
+ }
+}
diff --git a/confluence-plugin/src/main/java/com/networkedassets/autodoc/configuration/AdminConfigurationAction.java b/confluence-plugin/src/main/java/com/networkedassets/autodoc/configuration/AdminConfigurationAction.java
new file mode 100644
index 0000000..8570663
--- /dev/null
+++ b/confluence-plugin/src/main/java/com/networkedassets/autodoc/configuration/AdminConfigurationAction.java
@@ -0,0 +1,25 @@
+package com.networkedassets.autodoc.configuration;
+
+import com.atlassian.confluence.core.ConfluenceActionSupport;
+import org.apache.commons.io.IOUtils;
+
+import java.io.IOException;
+
+public class AdminConfigurationAction extends ConfluenceActionSupport {
+
+ public String load() {
+ return ConfluenceActionSupport.SUCCESS;
+ }
+
+ public String save() {
+ return ConfluenceActionSupport.SUCCESS;
+ }
+
+ public String getInnerHtml() throws IOException {
+ String html;
+ html = IOUtils.toString(
+ this.getClass().getClassLoader().getResourceAsStream("/configurationResources/configuration.html"));
+ html = (html.split("")[1]).split("")[0];
+ return html;
+ }
+}
\ No newline at end of file
diff --git a/confluence-plugin/src/main/java/com/networkedassets/autodoc/configuration/BundleAccessToken.java b/confluence-plugin/src/main/java/com/networkedassets/autodoc/configuration/BundleAccessToken.java
new file mode 100644
index 0000000..7e29f47
--- /dev/null
+++ b/confluence-plugin/src/main/java/com/networkedassets/autodoc/configuration/BundleAccessToken.java
@@ -0,0 +1,19 @@
+package com.networkedassets.autodoc.configuration;
+
+import net.java.ao.Entity;
+import net.java.ao.Preload;
+import net.java.ao.schema.Indexed;
+import net.java.ao.schema.Unique;
+
+@Preload
+public interface BundleAccessToken extends Entity {
+ @Indexed
+ @Unique
+ String getUserKey();
+ @Indexed
+ @Unique
+ void setUserKey(String userKey);
+
+ String getAccessToken();
+ void setAccessToken(String token);
+}
diff --git a/confluence-plugin/src/main/java/com/networkedassets/autodoc/configuration/BundleAccessTokenService.java b/confluence-plugin/src/main/java/com/networkedassets/autodoc/configuration/BundleAccessTokenService.java
new file mode 100644
index 0000000..d497043
--- /dev/null
+++ b/confluence-plugin/src/main/java/com/networkedassets/autodoc/configuration/BundleAccessTokenService.java
@@ -0,0 +1,78 @@
+package com.networkedassets.autodoc.configuration;
+
+import com.atlassian.activeobjects.external.ActiveObjects;
+import com.atlassian.confluence.user.AuthenticatedUserThreadLocal;
+import com.google.common.collect.ImmutableMap;
+import com.mashape.unirest.http.exceptions.UnirestException;
+import com.networkedassets.autodoc.TransformerClient;
+import com.networkedassets.util.functional.Optionals;
+import net.java.ao.Query;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+
+@Path("token")
+@Consumes("application/json")
+public class BundleAccessTokenService {
+
+ private TransformerClient transformerClient;
+ private ActiveObjects ao;
+
+ public BundleAccessTokenService(ActiveObjects ao, DocSettingsService docSettingsService) {
+ this.ao = ao;
+ this.transformerClient = new TransformerClient(docSettingsService, this);
+ }
+
+ public String getForUserKey(String userKey) throws TokenNotFoundException {
+ BundleAccessToken accessToken = null;
+
+ try {
+ accessToken = ao.executeInTransaction(() ->
+ ao.find(BundleAccessToken.class, Query.select().where("USER_KEY = ?", userKey))[0]
+ );
+ } catch (ArrayIndexOutOfBoundsException e) {
+ throw new TokenNotFoundException();
+ }
+
+ return accessToken.getAccessToken();
+ }
+
+ public void setForUserKey(String userKey, String token) {
+ ao.executeInTransaction(() -> {
+ BundleAccessToken accessToken =
+ Optionals.fromArrayOfOne(
+ ao.find(BundleAccessToken.class, Query.select().where("USER_KEY = ?", userKey))
+ ).orElse(
+ ao.create(BundleAccessToken.class, ImmutableMap.of("USER_KEY", userKey))
+ );
+ accessToken.setAccessToken(token);
+ accessToken.save();
+ return accessToken;
+ });
+ }
+
+ public void setForCurrentUser(String token) {
+ setForUserKey(AuthenticatedUserThreadLocal.get().getKey().getStringValue(), token);
+ }
+
+ @PUT
+ public void saveTokenForTransformerUser(Credentials credentials) throws UnirestException {
+ String token = transformerClient.getToken(credentials);
+ setForCurrentUser(token);
+ }
+
+ @GET
+ @Path("ask")
+ public boolean doesCurrentUserHaveToken() {
+ String userKey = AuthenticatedUserThreadLocal.get().getKey().getStringValue();
+ return ao.executeInTransaction(() ->
+ ao.find(BundleAccessToken.class, Query.select().where("USER_KEY = ?", userKey)).length == 1);
+ }
+
+ public static class Credentials {
+ public String username;
+ public String password;
+ }
+}
diff --git a/confluence-plugin/src/main/java/com/networkedassets/autodoc/configuration/ConfigurationService.java b/confluence-plugin/src/main/java/com/networkedassets/autodoc/configuration/ConfigurationService.java
new file mode 100644
index 0000000..d98af93
--- /dev/null
+++ b/confluence-plugin/src/main/java/com/networkedassets/autodoc/configuration/ConfigurationService.java
@@ -0,0 +1,55 @@
+package com.networkedassets.autodoc.configuration;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.mashape.unirest.http.exceptions.UnirestException;
+import com.networkedassets.autodoc.TransformerClient;
+import com.networkedassets.autodoc.documentation.transformer2.Bundle;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Response;
+import java.text.SimpleDateFormat;
+import java.util.List;
+
+@Path("/configuration/")
+public class ConfigurationService {
+
+ private static final Logger log = LoggerFactory.getLogger(ConfigurationService.class);
+ private static ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+ private final DocSettingsService docSettingsService;
+ private final TransformerClient transformerClient;
+
+ public ConfigurationService(DocSettingsService docSettingsService, BundleAccessTokenService bundleAccessTokenService) {
+ this.docSettingsService = docSettingsService;
+ transformerClient = new TransformerClient(docSettingsService, bundleAccessTokenService);
+
+ OBJECT_MAPPER.setDateFormat(new SimpleDateFormat("yyyy-MM-dd"));
+ OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+ }
+
+ @Path("transformerUrl")
+ @GET
+ public String getTransformerUrl() {
+ return docSettingsService.getTransformerUrl();
+ }
+
+ @Path("transformerUrl")
+ @POST
+ public void setTransformerUrl(String transformerUrl) {
+ docSettingsService.setTransformerUrl(transformerUrl);
+ }
+
+ @Path("bundles")
+ @GET
+ public Response getAllBundles(@HeaderParam("X-Macro-Owner") String macroOwnerKey) throws JsonProcessingException, UnirestException {
+ List res = transformerClient.getAllBundles(macroOwnerKey);
+ return Response.ok(OBJECT_MAPPER.writeValueAsString(res)).build();
+ }
+
+}
diff --git a/confluence-plugin/src/main/java/com/networkedassets/autodoc/configuration/DocSettingsService.java b/confluence-plugin/src/main/java/com/networkedassets/autodoc/configuration/DocSettingsService.java
new file mode 100644
index 0000000..f240b95
--- /dev/null
+++ b/confluence-plugin/src/main/java/com/networkedassets/autodoc/configuration/DocSettingsService.java
@@ -0,0 +1,50 @@
+package com.networkedassets.autodoc.configuration;
+
+import com.atlassian.core.util.ClassLoaderUtils;
+import com.atlassian.sal.api.pluginsettings.PluginSettings;
+import com.atlassian.sal.api.pluginsettings.PluginSettingsFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+@SuppressWarnings("WeakerAccess")
+public class DocSettingsService {
+ public static final String TRANSFORMER_URL = "com.networkedassets.autodoc.configuration.TRANSFORMER_URL";
+ private final Logger log = LoggerFactory.getLogger(DocSettingsService.class);
+ private final PluginSettings pluginSettings;
+
+ public DocSettingsService(PluginSettingsFactory pluginSettingsFactory) {
+ pluginSettings = pluginSettingsFactory.createGlobalSettings();
+ }
+
+ public String getTransformerUrl() {
+ String url;
+ url = (String) pluginSettings.get(TRANSFORMER_URL);
+ if (url == null) {
+ url = getTransformerUrlFromConfigFile();
+ pluginSettings.put(TRANSFORMER_URL, url);
+ }
+ return url;
+ }
+
+ private String getTransformerUrlFromConfigFile() {
+ InputStream properties = ClassLoaderUtils.getResourceAsStream("autodoc_confluence.properties", getClass());
+ Properties props = new Properties();
+ try {
+ props.load(properties);
+ } catch (IOException e) {
+ log.error("Couldn't load the configuration file", e);
+ }
+ return props.getProperty("transformerUrl", "https://localhost:8080/transformer");
+ }
+
+ public void setTransformerUrl(String transformerUrl) {
+ if (transformerUrl.endsWith("/")) {
+ transformerUrl = transformerUrl.substring(0, transformerUrl.length() - 1);
+ }
+ pluginSettings.put(TRANSFORMER_URL, transformerUrl);
+ }
+}
diff --git a/confluence-plugin/src/main/java/com/networkedassets/autodoc/configuration/TokenNotFoundException.java b/confluence-plugin/src/main/java/com/networkedassets/autodoc/configuration/TokenNotFoundException.java
new file mode 100644
index 0000000..f857cb1
--- /dev/null
+++ b/confluence-plugin/src/main/java/com/networkedassets/autodoc/configuration/TokenNotFoundException.java
@@ -0,0 +1,4 @@
+package com.networkedassets.autodoc.configuration;
+
+public class TokenNotFoundException extends Exception {
+}
diff --git a/confluence-plugin/src/main/java/com/networkedassets/autodoc/documentation/Documentation.java b/confluence-plugin/src/main/java/com/networkedassets/autodoc/documentation/Documentation.java
new file mode 100644
index 0000000..da06c9c
--- /dev/null
+++ b/confluence-plugin/src/main/java/com/networkedassets/autodoc/documentation/Documentation.java
@@ -0,0 +1,37 @@
+package com.networkedassets.autodoc.documentation;
+
+import java.util.List;
+
+public class Documentation {
+ private String documentationType;
+ private String bundle;
+ private List documentationPieces;
+
+ public String getDocumentationType() {
+ return documentationType;
+ }
+
+ public Documentation setDocumentationType(String documentationType) {
+ this.documentationType = documentationType;
+ return this;
+ }
+
+
+ public List getDocumentationPieces() {
+ return documentationPieces;
+ }
+
+ public Documentation setDocumentationPieces(List documentationPieces) {
+ this.documentationPieces = documentationPieces;
+ return this;
+ }
+
+ public String getBundle() {
+ return bundle;
+ }
+
+ public Documentation setBundle(String bundle) {
+ this.bundle = bundle;
+ return this;
+ }
+}
diff --git a/confluence-plugin/src/main/java/com/networkedassets/autodoc/documentation/DocumentationPiece.java b/confluence-plugin/src/main/java/com/networkedassets/autodoc/documentation/DocumentationPiece.java
new file mode 100644
index 0000000..f2437e1
--- /dev/null
+++ b/confluence-plugin/src/main/java/com/networkedassets/autodoc/documentation/DocumentationPiece.java
@@ -0,0 +1,46 @@
+package com.networkedassets.autodoc.documentation;
+
+public class DocumentationPiece {
+ private String pieceName;
+ private String pieceType;
+ private String content;
+ private Documentation documentation;
+
+ public String getPieceName() {
+ return pieceName;
+ }
+
+ public void setPieceName(String name) {
+ this.pieceName = name;
+ }
+
+ /**
+ * Type of this documentation piece. Ex. for piece of javadoc this may be "class", "package"
+ */
+ public String getPieceType() {
+ return pieceType;
+ }
+
+ public DocumentationPiece setPieceType(String pieceType) {
+ this.pieceType = pieceType;
+ return this;
+ }
+
+ public String getContent() {
+ return content;
+ }
+
+ public DocumentationPiece setContent(String content) {
+ this.content = content;
+ return this;
+ }
+
+ public Documentation getDocumentation() {
+ return documentation;
+ }
+
+ public DocumentationPiece setDocumentation(Documentation documentation) {
+ this.documentation = documentation;
+ return this;
+ }
+}
diff --git a/confluence-plugin/src/main/java/com/networkedassets/autodoc/documentation/DocumentationProxyResource.java b/confluence-plugin/src/main/java/com/networkedassets/autodoc/documentation/DocumentationProxyResource.java
new file mode 100644
index 0000000..ca1e0c4
--- /dev/null
+++ b/confluence-plugin/src/main/java/com/networkedassets/autodoc/documentation/DocumentationProxyResource.java
@@ -0,0 +1,52 @@
+package com.networkedassets.autodoc.documentation;
+
+import com.mashape.unirest.http.HttpResponse;
+import com.mashape.unirest.http.Unirest;
+import com.mashape.unirest.http.exceptions.UnirestException;
+import com.mashape.unirest.request.GetRequest;
+import com.networkedassets.autodoc.configuration.BundleAccessTokenService;
+import com.networkedassets.autodoc.configuration.DocSettingsService;
+import com.networkedassets.autodoc.configuration.TokenNotFoundException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.*;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+@Path("/transformer/")
+@Produces({MediaType.APPLICATION_JSON})
+public class DocumentationProxyResource {
+
+ private BundleAccessTokenService bundleAccessTokenService;
+
+ private DocSettingsService docSettingsService;
+
+ public DocumentationProxyResource(BundleAccessTokenService bundleAccessTokenService, DocSettingsService docSettingsService) {
+ this.bundleAccessTokenService = bundleAccessTokenService;
+ this.docSettingsService = docSettingsService;
+ }
+
+ @GET
+ @Path("{path:.*}")
+ public Response proxy(@HeaderParam("X-Macro-Owner") String macroOwner, @PathParam("path") String path, @Context HttpServletRequest request) {
+ try {
+ String url = docSettingsService.getTransformerUrl() + "/rest/" + path + ((request.getQueryString() != null) ? "?" + request.getQueryString() : "");
+
+ GetRequest unirestRequest = Unirest.get(url)
+ .header("Authorization", "Bearer " + bundleAccessTokenService.getForUserKey(macroOwner));
+ HttpResponse response = unirestRequest
+ .asString();
+
+ return Response
+ .status(response.getStatus())
+ .entity(response.getBody())
+ .header("Content-Type", response.getHeaders().get("Content-Type"))
+ .build();
+ } catch (UnirestException e) {
+ return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("Unirest exception").build();
+ } catch (TokenNotFoundException e) {
+ return Response.status(Response.Status.UNAUTHORIZED).build();
+ }
+ }
+}
diff --git a/confluence-plugin/src/main/java/com/networkedassets/autodoc/documentation/DocumentationRepository.java b/confluence-plugin/src/main/java/com/networkedassets/autodoc/documentation/DocumentationRepository.java
new file mode 100644
index 0000000..d34d701
--- /dev/null
+++ b/confluence-plugin/src/main/java/com/networkedassets/autodoc/documentation/DocumentationRepository.java
@@ -0,0 +1,65 @@
+package com.networkedassets.autodoc.documentation;
+
+import com.mashape.unirest.http.exceptions.UnirestException;
+import com.networkedassets.autodoc.TransformerClient;
+import com.networkedassets.autodoc.configuration.BundleAccessTokenService;
+import com.networkedassets.autodoc.configuration.DocSettingsService;
+import com.networkedassets.util.functional.Throwing;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+public class DocumentationRepository {
+ private TransformerClient tc;
+
+ public DocumentationRepository(
+ DocSettingsService docSettingsService,
+ BundleAccessTokenService bundleAccessTokenService
+ ) {
+ this.tc = new TransformerClient(docSettingsService, bundleAccessTokenService);
+ }
+
+ public Optional findDocumentation(
+ String macroOwnerKey,
+ int bundleId,
+ String documentationType
+ ) {
+ try {
+ return tc.getBundleById(macroOwnerKey, bundleId).flatMap(Throwing.functionRethrowAsRuntimeException(
+ bundle -> tc.getDocumentation(macroOwnerKey, bundle, documentationType)));
+ } catch (UnirestException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public Optional findDocumentationPiece(
+ String macroOwnerKey,
+ int bundleId,
+ String docType,
+ String docPieceName
+ ) {
+ return findDocumentation(macroOwnerKey, bundleId, docType)
+ .flatMap(d -> findDocumentationPieceInDocumentation(d, docPieceName));
+ }
+
+ public Optional findDocumentationPieceInDocumentation(Documentation doc, String docPieceName) {
+ return doc.getDocumentationPieces().stream().filter(dp -> docPieceName.equals(dp.getPieceName())).findAny();
+ }
+
+ public List findDocumentationPieceWithQuery(
+ String macroOwnerKey,
+ int bundleId,
+ String doctype,
+ String query
+ ) {
+ Optional documentation = findDocumentation(macroOwnerKey, bundleId, doctype);
+ return documentation.map(doc ->
+ doc.getDocumentationPieces().parallelStream()
+ .filter(dp -> Pattern.compile(query).matcher(dp.getContent()).find())
+ .collect(Collectors.toList())
+ ).orElse(Collections.emptyList());
+ }
+}
diff --git a/confluence-plugin/src/main/java/com/networkedassets/autodoc/documentation/DocumentationService.java b/confluence-plugin/src/main/java/com/networkedassets/autodoc/documentation/DocumentationService.java
new file mode 100644
index 0000000..b88848c
--- /dev/null
+++ b/confluence-plugin/src/main/java/com/networkedassets/autodoc/documentation/DocumentationService.java
@@ -0,0 +1,127 @@
+package com.networkedassets.autodoc.documentation;
+
+import com.atlassian.json.jsonorg.JSONException;
+import com.atlassian.json.jsonorg.JSONObject;
+import com.google.common.base.Joiner;
+import com.google.common.base.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.*;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+@Path("/documentation/")
+@Produces({MediaType.APPLICATION_JSON})
+public class DocumentationService {
+ private final String ERROR_JSON = "{\"success\": false, \"message\": \"Could not find requested documentation!\"}";
+ private DocumentationRepository docRepository;
+ @SuppressWarnings("unused")
+ private Logger log = LoggerFactory.getLogger(DocumentationService.class);
+
+ public DocumentationService(DocumentationRepository docRepository) {
+ this.docRepository = docRepository;
+ }
+
+ @Path("{bundle}/{doctype}")
+ @GET
+ public Response getDocumentationPiecesForProject(
+ @HeaderParam("X-Macro-Owner") String macroOwnerKey,
+ @PathParam("bundle") int bundle,
+ @PathParam("doctype") String doctype
+ ) throws UnsupportedEncodingException {
+ String doctypeDec = URLDecoder.decode(doctype, "UTF-8");
+
+ if ("uml".equalsIgnoreCase(doctypeDec))
+ return getDocumentationPiece(macroOwnerKey, bundle, doctypeDec, "all");
+ return docRepository.findDocumentation(macroOwnerKey, bundle, doctypeDec)
+ .map(d -> Response.ok("{\"success\": true, \"documentationPieces\": [" +
+ d.getDocumentationPieces().stream()
+ .map(dp -> "{\"type\": \"" + dp.getPieceType() + "\","
+ + "\"name\": \"" + dp.getPieceName() + "\"}")
+ .collect(Collectors.joining(",")) +
+ "]}"))
+ .orElse(Response.status(404).entity(ERROR_JSON)).build();
+ }
+
+ @Path("{bundle}/{doctype}/{docPieceName}")
+ @GET
+ public Response getDocumentationPiece(
+ @HeaderParam("X-Macro-Owner") String macroOwnerKey,
+ @PathParam("bundle") int bundle,
+ @PathParam("doctype") String docType,
+ @PathParam("docPieceName") String docPieceName
+ ) throws UnsupportedEncodingException {
+ String doctypeDec = URLDecoder.decode(docType, "UTF-8");
+ String docPieceNameDec = URLDecoder.decode(docPieceName, "UTF-8");
+
+ Optional documentationPiece =
+ docRepository.findDocumentationPiece(macroOwnerKey, bundle, doctypeDec, docPieceNameDec);
+
+ return documentationPiece.map(this::makeDocPieceJson)
+ .map(n -> Response.ok(n).build())
+ .orElse(Response.status(404).entity(ERROR_JSON).build());
+ }
+
+ @Path("{bundle}/{doctype}/{docPieceName}/{attribute}")
+ @GET
+ public Response getDocumentationPieceByAttribute(
+ @HeaderParam("X-Macro-Owner") String macroOwnerKey,
+ @PathParam("bundle") int bundle,
+ @PathParam("doctype") String docType,
+ @PathParam("docPieceName") String docPieceName,
+ @PathParam("attribute") String attribute
+ ) throws UnsupportedEncodingException {
+ String doctypeDec = URLDecoder.decode(docType, "UTF-8");
+ String docPieceNameDec = URLDecoder.decode(docPieceName, "UTF-8");
+ String attributeDec = URLDecoder.decode(attribute, "UTF-8");
+
+ Optional documentationPiece =
+ docRepository.findDocumentationPiece(macroOwnerKey, bundle, doctypeDec, docPieceNameDec);
+
+ return documentationPiece.map(docPiece -> makeDocPieceJson(docPiece, attributeDec))
+ .map(n -> Response.ok(n).build())
+ .orElse(Response.status(404).entity(ERROR_JSON).build());
+ }
+
+ private String makeDocPieceJson(DocumentationPiece dp) {
+ return dp.getContent();
+ }
+
+ private String makeDocPieceJson(DocumentationPiece dp, String attribute) {
+ JSONObject jsonObject = new JSONObject(dp.getContent());
+ try {
+ return String.format("{\"%s\": \"%s\"}", attribute, jsonObject.getString(attribute));
+ } catch (JSONException e) {
+ return null;
+ }
+ }
+
+ @Path("{bundle}/{doctype}/search")
+ @GET
+ public Response searchDocumentation(
+ @HeaderParam("X-Macro-Owner") String macroOwnerKey,
+ @PathParam("bundle") int bundle,
+ @PathParam("doctype") String doctype,
+ @QueryParam("q") String query
+ ) throws UnsupportedEncodingException {
+
+ if (Strings.isNullOrEmpty(query)) return Response.ok("{\"results\": []}").build();
+ String queryDec = URLDecoder.decode(query, "UTF-8");
+ String doctypeDec = URLDecoder.decode(doctype, "UTF-8");
+
+ List searchResult =
+ docRepository.findDocumentationPieceWithQuery(macroOwnerKey, bundle, doctypeDec, queryDec);
+
+ final List results = searchResult.stream()
+ .map(dp -> "\"" + dp.getPieceName() + "\"")
+ .collect(Collectors.toList());
+
+ return Response.ok(String.format("{\"results\": [%s]}", Joiner.on(",").join(results))).build();
+ }
+}
diff --git a/confluence-plugin/src/main/java/com/networkedassets/autodoc/documentation/transformer2/Bundle.java b/confluence-plugin/src/main/java/com/networkedassets/autodoc/documentation/transformer2/Bundle.java
new file mode 100644
index 0000000..fa38f73
--- /dev/null
+++ b/confluence-plugin/src/main/java/com/networkedassets/autodoc/documentation/transformer2/Bundle.java
@@ -0,0 +1,29 @@
+package com.networkedassets.autodoc.documentation.transformer2;
+
+public class Bundle {
+ private int id;
+ private String name;
+
+ public Bundle(int id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public Bundle setId(int id) {
+ this.id = id;
+ return this;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Bundle setName(String name) {
+ this.name = name;
+ return this;
+ }
+}
diff --git a/confluence-plugin/src/main/java/com/networkedassets/autodoc/documentation/transformer2/DocItem.java b/confluence-plugin/src/main/java/com/networkedassets/autodoc/documentation/transformer2/DocItem.java
new file mode 100644
index 0000000..2e53d56
--- /dev/null
+++ b/confluence-plugin/src/main/java/com/networkedassets/autodoc/documentation/transformer2/DocItem.java
@@ -0,0 +1,18 @@
+package com.networkedassets.autodoc.documentation.transformer2;
+
+public class DocItem {
+ private int id;
+
+ public DocItem(int id) {
+ this.id = id;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public DocItem setId(int id) {
+ this.id = id;
+ return this;
+ }
+}
diff --git a/confluence-plugin/src/main/java/com/networkedassets/autodoc/documentation/transformer2/DocItemSet.java b/confluence-plugin/src/main/java/com/networkedassets/autodoc/documentation/transformer2/DocItemSet.java
new file mode 100644
index 0000000..99b089e
--- /dev/null
+++ b/confluence-plugin/src/main/java/com/networkedassets/autodoc/documentation/transformer2/DocItemSet.java
@@ -0,0 +1,45 @@
+package com.networkedassets.autodoc.documentation.transformer2;
+
+import java.util.List;
+
+public class DocItemSet {
+ public static final String UML_TYPE = "CLASS_DIAGRAM";
+ public static final String JAVADOC_TYPE = "JSON";
+
+ private String type;
+ private List docItems;
+ private int id;
+
+ public DocItemSet(String type, List docItems, int id) {
+ this.type = type;
+ this.docItems = docItems;
+ this.id = id;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public DocItemSet setType(String type) {
+ this.type = type;
+ return this;
+ }
+
+ public List getDocItems() {
+ return docItems;
+ }
+
+ public DocItemSet setDocItems(List docItems) {
+ this.docItems = docItems;
+ return this;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public DocItemSet setId(int id) {
+ this.id = id;
+ return this;
+ }
+}
diff --git a/confluence-plugin/src/main/resources/atlassian-plugin.xml b/confluence-plugin/src/main/resources/atlassian-plugin.xml
new file mode 100644
index 0000000..c19d774
--- /dev/null
+++ b/confluence-plugin/src/main/resources/atlassian-plugin.xml
@@ -0,0 +1,150 @@
+
+
+
+
+ ${project.description}
+ ${project.version}
+
+ images/pluginIcon.png
+ images/pluginLogo.png
+ images/vendorLogo.png
+ images/vendorIcon.png
+ /admin/plugins/autodoc/config.action
+
+ false
+
+
+
+
+
+
+
+
+ autodoc_confluence
+
+
+
+ confluence.editor.actions:editor-macro-browser
+
+ macro-browser
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ com.atlassian.soy.soy-template-plugin:soy-deps
+
+
+
+
+
+
+
+
+ autodoc_confluence
+
+
+
+
+
+
+
+
+
+
+
+
+ Component to access Active Objects functionality from the
+ plugin
+
+
+
+
+
+
+
+
+
+
+ /configurationResources/adminConfiguration.vm
+
+ /configurationResources/adminConfiguration.vm
+
+
+
+
+ /configurationResources/adminConfiguration.vm
+
+ /admin/plugins/autodoc/config.action
+
+
+
+
+
+
+
+
+ DoC macro displaying documentation in various forms on pages
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Provides REST endpoints used by DoC
+
+
+
+
+
+
+
+ com.networkedassets.autodoc.configuration.BundleAccessToken
+
+
diff --git a/confluence-plugin/src/main/resources/autodoc_confluence.properties b/confluence-plugin/src/main/resources/autodoc_confluence.properties
new file mode 100644
index 0000000..2a4929d
--- /dev/null
+++ b/confluence-plugin/src/main/resources/autodoc_confluence.properties
@@ -0,0 +1,7 @@
+#put any key/value pairs here
+my.plugin.name=Autodoc
+autodoc-configuration-link.label=Autodoc Configuration Link
+autodoc-configuration-link.name=Autodoc Configuration Link
+autodoc-configuration-link.description=The Autodoc Configuration Link Plugin
+autodoc-configuration-action.on-set-message=Configuration saved!
+transformerUrl=http://localhost:8080/transformer
diff --git a/confluence-plugin/src/main/resources/configurationResources/adminConfiguration.vm b/confluence-plugin/src/main/resources/configurationResources/adminConfiguration.vm
new file mode 100644
index 0000000..85d8dca
--- /dev/null
+++ b/confluence-plugin/src/main/resources/configurationResources/adminConfiguration.vm
@@ -0,0 +1,20 @@
+#set ( $d = "$")
+
+
+ Configure DoC
+
+
+ #requireResource("confluence.web.resources:ajs")
+ #requireResource("com.atlassian.auiplugin:aui-select2")
+ #requireResource("com.atlassian.auiplugin:aui-toggle")
+ #requireResource("com.atlassian.auiplugin:dialog2")
+ #requireResource("com.networkedassets.autodoc.confluence-plugin:configuration-resources")
+ #putMetadata('configLocation', "admin")
+
+
+
+ #parse ( "/template/includes/actionmessages.vm" )
+ #parse ( "/template/includes/actionerrors.vm" )
+ $innerHtml
+
+
\ No newline at end of file
diff --git a/confluence-plugin/src/main/resources/configurationResources/configuration.html b/confluence-plugin/src/main/resources/configurationResources/configuration.html
new file mode 100644
index 0000000..e32dbd8
--- /dev/null
+++ b/confluence-plugin/src/main/resources/configurationResources/configuration.html
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+