Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding hot fix to patch the user id, this avoids to set the userId as… #1

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Empty file.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Empty file.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#Tue Dec 07 14:03:39 CST 2021
gradle.version=4.10.2
Binary file not shown.
Binary file not shown.
Empty file.
8 changes: 8 additions & 0 deletions com.dotcms.override.user/.idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions com.dotcms.override.user/.idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions com.dotcms.override.user/.idea/codeStyles/codeStyleConfig.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions com.dotcms.override.user/.idea/compiler.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions com.dotcms.override.user/.idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions com.dotcms.override.user/.idea/jarRepositories.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions com.dotcms.override.user/.idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions com.dotcms.override.user/.idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

95 changes: 95 additions & 0 deletions com.dotcms.override.user/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# README

This bundle plugin is an example of how to override dotCMS classes with our bundle plugin.

## How to build this example

To install all you need to do is build the JAR. to do this run
`./gradlew jar`

This will build two jars in the `build/libs` directory: a bundle fragment (in order to expose needed 3rd party libraries from dotCMS) and the plugin jar

* **To install this bundle:**

Copy the bundle jar files inside the Felix OSGI container (*dotCMS/felix/load*).

OR

Upload the bundle jars files using the dotCMS UI (*CMS Admin->Dynamic Plugins->Upload Plugin*).

* **To uninstall this bundle:**

Remove the bundle jars files from the Felix OSGI container (*dotCMS/felix/load*).

OR

Undeploy the bundle jars using the dotCMS UI (*CMS Admin->Dynamic Plugins->Undeploy*).

## How to create a bundle plugin to override dotCMS classes

In order to create this OSGI plugin, you must create a `META-INF/MANIFEST` to be inserted into OSGI jar.
This file is being created for you by Gradle. If you need you can alter our config for this but in general our out of the box config should work.
The Gradle plugin uses BND to generate the Manifest. The main reason you need to alter the config is when you need to exclude a package you are including on your Bundle-ClassPath

If you are building the MANIFEST on your own or desire more info on it below is a description of what is required in this MANIFEST you must specify (see template plugin):

```
Bundle-Name: The name of your bundle
Bundle-SymbolicName: A short an unique name for the bundle
Bundle-Activator: Package and name of your Activator class (example: com.dotmarketing.osgi.override.Activator)
Override-Classes: Comma separated list of classes.
List of classes we are trying to override, in order to override any dotCMS class is mandatory to add it to this list because dotCMS implementation of the class will be already loaded by the dotCMS class loader so if we don't explicit specify the classes to override the class loader wont try to load them.
Export-Package: Declares the packages that are visible outside the plugin. Any package not declared here has visibility only within the bundle.
Import-Package: This is a comma separated list of the names of packages to import. In this list there must be the packages that you are using inside your osgi bundle plugin and are exported and exposed by the dotCMS runtime.
```

## Beware (!)

In order to work inside the Apache Felix OSGI runtime, the import and export directive must be bidirectional, there are two ways to accomplish this:

* **Exported Packages**

The dotCMS must declare the set of packages that will be available to the OSGI plugins by changing the file: *dotCMS/WEB-INF/felix/osgi-extra.conf*.
This is possible also using the dotCMS UI (*CMS Admin->Dynamic Plugins->Exported Packages*).

Only after that exported packages are defined in this list, a plugin can Import the packages to use them inside the OSGI blundle.

* **Fragment**

A Bundle fragment, is a bundle whose contents are made available to another bundles exporting 3rd party libraries from dotCMS.
One notable difference is that fragments do not participate in the lifecycle of the bundle, and therefore cannot have an Bundle-Activator.
As it not contain a Bundle-Activator a fragment cannot be started so after deploy it will have its state as Resolved and NOT as Active as a normal bundle plugin.

---
## Components

### com.dotmarketing.portlets.folders.model.Folder

Copy of the original *com.dotmarketing.portlets.folders.model.Folder* that lives inside dotCMS but with small changes (Just logging code) inside the `getPath()` method in order to demonstrate we can override a dotCMS class with our implementation.

### Activator

This bundle activator extends from *com.dotmarketing.osgi.GenericBundleActivator* and implements `BundleActivator.start()`.

* PLEASE note the `initializeServices( context )` call, this call is MANDATORY (!) as it will allow us to share resources between the bundle and the host container (dotCMS) and override classes.

---
## Testing

For our redefinition of the class *com.dotmarketing.portlets.folders.model.Folder* we modified the body of the `getPath()` method, we added some debugging lines in order to prove it is working.
The *Folder* class is call it by our activator (*com.dotmarketing.osgi.override.Activator*) which prove the OSGI bundle is using our redefinition of the Folder class, but in order to demonstrate the dotCMS context is using it too go to:
*dotCMS Admin -> Site Browser -> Select any folder on the tree -> Add Folder*.

The *Add Folder* uses the *Folder* class and if you deployed your OSGI plugin the debugging code we added should be visible on the logs.

---

## Limitations (!)

There are limitations on the hot deploy functionality for the OSGI Override plugin, there are some rules for the code you can modify on the redefined classes in order to see those changes when you upload the plugin.

In order to support the overriding of a class inside ours OSGI plugins we use the java hot swapping, it allows to redefine classes, unfortunately, this redefinition is limited only to changing method bodies:

> The redefinition may change method bodies, the constant pool and attributes. The redefinition must not add, remove or rename fields or methods, change the signatures of methods, or change inheritance.

As long as you don't add, remove or change methods (ONLY the methods bodies) for your redefined classes you will have an OSGI plugin that will reflect you changes when a deploy is done.
103 changes: 103 additions & 0 deletions com.dotcms.override.user/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
plugins {
id 'biz.aQute.bnd.builder' version '3.3.0'
}

sourceCompatibility = '1.8'
version = '0.2'

repositories {
maven { url "http://repo.dotcms.com/artifactory/libs-release" }
}

dependencies {
compile('com.dotcms:dotcms:21.11') { transitive = true }
}

import java.util.jar.*

/////////////////////////
//Plugin jar
/////////////////////////
jar {
manifest {
attributes (
'Bundle-Vendor': 'dotCMS',
'Bundle-Description': 'dotCMS - Override class example',
'Bundle-DocURL': 'https://dotcms.com/',
'Bundle-Activator': 'com.dotmarketing.osgi.override.Activator',
'Override-Classes': 'com.liferay.portal.model.UserModel',
'Import-Package': '!com.liferay.portal.model,*;version=0'
)
}
}
jar.finalizedBy 'fragmentJar'

/////////////////////////
//Fragment jar
/////////////////////////

ext {
bundleName = "dotCMS Override fragment"
bundleDescription = "dotCMS - Override fragment"
fragmentHost = "system.bundle; extension:=framework"
bundleSymbolicName = "" //Auto generated based on the plugin jar
bundleVersion = "" //Auto generated based on the plugin jar
importPackage = "" //Auto generated based on the plugin jar
bundleManifestVersion = "" //Auto generated based on the plugin jar
bundleDocURL = "" //Auto generated based on the plugin jar
bundleVendor = "" //Auto generated based on the plugin jar
}
/**
* The import generates versions like this: version="[1.8,2)"
* That format does not work for the export, so we need to replace it
* to: version=0
*/
ext.fixVersionNumber = {importValue ->
return importValue.replaceAll("\"\\[[0-9.,]+\\)\"", "0")
}

/**
* Reads the Manifest file of the just created plugin jar in order to get the required info
* to automatically create the fragment jar.
*/
task readManifesttAttributes {
doFirst {
File file = configurations.baseline.singleFile
JarFile jar = new JarFile(file)
Attributes manifest = jar.getManifest().getMainAttributes()
bundleSymbolicName = "${manifest.getValue('Bundle-SymbolicName')}"
bundleVersion = "${manifest.getValue('Bundle-Version')}"
importPackage = "${manifest.getValue('Import-Package')}"
bundleManifestVersion = "${manifest.getValue('Bundle-ManifestVersion')}"
bundleDocURL = "${manifest.getValue('Bundle-DocURL')}"
bundleVendor = "${manifest.getValue('Bundle-Vendor')}"
}
}
task fragmentJar(type: Jar) {

doFirst {
//Setting the fragment jar name
baseName = project.name
archiveName = "${baseName}.fragment-${version}.jar"
importPackage = fixVersionNumber(importPackage)

manifest {
attributes (
'Bundle-Name': "${bundleName}",
'Bundle-Description': "${bundleDescription}",
'Bundle-Vendor': "${bundleVendor}",
'Bundle-Version': "${version}",
'Bundle-SymbolicName': "${baseName}.fragment",
'Bundle-ManifestVersion': "${bundleManifestVersion}",
'Bundle-DocURL': "${bundleDocURL}",
'Fragment-Host': "${fragmentHost}",
'Export-Package': "${importPackage}"
)
}
}
}
fragmentJar.dependsOn 'readManifesttAttributes'

task wrapper(type: Wrapper) {
gradleVersion = '4.10.2'
}
Binary file not shown.
Binary file not shown.
Loading