Adding Custom Code to uPortal-start
Previously in this series, we covered suggestions on how to write customizations for uPortal 5 using Decorator and Strategy patterns. Here, our last post, we cover how to add such custom classes to your uPortal-start repo.
Again, a word of caution. We have found that local customizations, as opposed to adding changes back to the official uPortal repositories, usually entail severe costs. First, others may be interested in your changes, or might even leverage Strategy refactors for their own custom classes. Second, other uPortal developers will be more apt to support your code if it is in the public repo. If you keep it local, they have no idea if changes will break your code. Third, staying current with uPortal upstream patches is easier when you don’t have to worry about a conflict with your custom code. Fourth, you don’t need to invest time isolating custom code changes, that can be hard to unwind as time passes, especially after a few years of local changes mixed with upstream patches. Fifth, your code may receive free enhancements as others adopt it. I am sure there are other advantages.
I see one major disadvantage. Others may want to adopt your change and modify it to further reflect their needs. These needs may differ from yours, so some guarding of your feature may be needed. Then again, Decorator and Strategy patterns provide a means to allow for differing approaches. This risk is very minor in light of the strong advantages of sharing your code.
Okay, I have not convinced you. You are dead-set on keeping your code local to your organization. Let’s go over the nuts and bolts of making a custom module to hold your code in your local uPortal-start repo.
The first step is to create a directory named custom. The name is arbitrary, but we might as well follow convention.
```
$ mkdir custom
```
Oh, I am going to assume a Linux or MacOS operating system. Windows is fine, but in that case, I strongly suggest Cygwin to mimic a Linux console.
Next, we need to consider what module in uPortal (or portlet) our custom classes match. For example, you may have a custom Person Attribute Group (PAG) tester. These are found in uPortal-groups. We also need a prefix, usually your institution’s abbreviation. For our example we will use mcs.
Armed with this information, we can create a subdirectory in custom for our custom classes. A name like mcs-groups would capture enough meaning for others to quickly grasp some idea of what area the customization entails. Again, the name is arbitrary, but a naming convention should be used. Why a subdirectory? We found that once we are capturing local changes, there are a few areas that are customized. We could toss all the custom source in custom and use it as the base for all local code, but specificity has value as projects age. In contrast, portlets are specific enough that a single custom portlet directory under custom usually suffices, custom/mcs-notifications for example.
```
$ cd custom
$ mkdir mcs-groups
```
Continuing with directories and convention, we next create src/main/ and src/test/ for our code and any tests. This convention is followed by almost all uPortal projects, stemming from Maven conventions.
```
$ cd mcs-groups
$ mkdir -p src/main
$ mkdir src/test
```
Now, you can add your Java source files. We will not cover building a directory structure here; however, a glance at portlets and uPortal repos on GitHub should provide plenty of examples.
The last step in these custom directories is to set up build.gradle in each. There are four sections we commonly define in these custom Gradle build files. We want to have a description to document the customization -- even if it is just to declare the obvious. We need to apply some Gradle plugins for Java and Eclipse (a common IDE). Third, we need to define the repositories we need to search for artifacts. We wrap up with dependencies, where most of our effort rests. The plugins and repositories are almost boilerplate. Dependencies will vary and often entail a bit of experimentation or vigorous review of class imports. Here’s an example:
```
description = "MCS Custom PAGS Testers"
apply plugin: 'java'
apply plugin: 'eclipse'
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
compile "org.jasig.portal:uPortal-groups-core:${uPortalVersion}"
compileOnly "${servletApiDependency}"
}
```
There are a number of build.gradle files in uPortal-start. If you need to reference a portlet, look at the related build.gradle in the overlays directory to see how to create a portlet dependency for compile-time.
We are almost done! The last step is to add your custom modules to the overall Gradle project. This is done in settings.gradle in the root directory of your uPortal-start repo. Add an include for each subdirectory under custom:
```
// Custom MCS Modules
Include ‘custom:mcs-groups’
```
Note that the directory names map directly to the module path and name.
These are the steps to add custom code to your uPortal-start repo for use in your portal service. Once you have the classes in your project, you will likely edit overridesContext.xml files in the uPortal or portlet overlay directories to define beans of these classes.
Often, beans will need to match unique names to supersede beans in the official projects. On rare occasions, the beans should have their own names. The latter case occurs when some bean, usually a service, is configured to take any beans of a certain interface for processing. Again, this is uncommon.
If you followed this entire series and have some experience with uPortal, you should be well-equipped to submit quality pull requests and even set up local code for your uPortal-start repo! If you have questions, please feel free to ask for help on the uPortal mailing lists or start a conversation with us to discuss your needs!
Useful Reading:
- Customizing uPortal (Part 1): Using Design Patterns
- Customizing uPortal (Part 2): Using the Decorator Design Pattern
- Customizing uPortal (Part 3): Using the Strategy Design Pattern
- Customizing uPortal (Part 4): Adding Custom Code to uPortal-start