[oXygen-user] Web Author and more then one git submodules

oXygen XML Editor Support (Gabriel Titerlea) support at oxygenxml.com
Fri Dec 6 06:54:04 CST 2019


Regarding Web Author, we'll retain the current behavior regarding git 
sub-modules for now.

But for your use-case we think allowing users to switch the file-browser 
to the parent repository and choosing a file from there is a good 
To make this work you will need to add custom code that transforms 
absolute URLs into relative URLs and vice versa while taking into 
account sub-modules.

To do that there are 3 hooks where you should intervene using a custom 
Web Author plugin [1][2].

1. Add a URI resolver [3] which will be used to resolve relative paths 
to absolute paths.
2. Add a Relative Reference Resolver which will be used to resolve 
absolute paths to relative paths on the server side.
3. Add a Relative Reference Resolver which will be used to resolve 
absolute paths to relative paths on the client side.

I'm attaching an example for points 1 & 2:

    package example.plugin

    import java.net.MalformedURLException;
    import java.net.URI;
    import java.net.URISyntaxException;
    import java.net.URL;
    import java.util.Optional;
    import java.util.function.Predicate;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;

    import javax.xml.transform.Source;
    import javax.xml.transform.TransformerException;
    import javax.xml.transform.URIResolver;

    import ro.sync.basic.util.URLUtil;
    import ro.sync.exml.plugin.workspace.WorkspaceAccessPluginExtension;
    import ro.sync.exml.workspace.api.standalone.StandalonePluginWorkspace;

    public class MyWorkspaceAccessPluginExtension implements
    WorkspaceAccessPluginExtension {

        * Predicate to check if a URL is inside a configured parent
        * You can hard-code this, save it in an option or determine it
    dynamically depending on your use-case.
        * */
       private Predicate<String> urlIsInsideParentRepository =

        * This regExp extract first part of a Git URL, without the path
        * More details about Git URLs:
        * In this example I'm looking at `gitgle` URLs which are URLs
    for GitLab on-premise.
       private Pattern gitUrlWithoutPathPattern =

        * The URL of the submodule inside a parent repository.
       private String submoduleUrlInsideParent =

       URIResolver uriResolver = new URIResolver() {
         public Source resolve(String href, String base) throws
    TransformerException {

           try {
             Optional<String> pathRelativeToParentRepo =
    getPathRelativeToSubmoduleInParentRepo(href, base);

             if (pathRelativeToParentRepo.isPresent()) {
               URI uriInParentRepo = new URI(submoduleUrlInsideParent +

               URL normalizedUrlInParentRepo =

                * Attach session information to the URL.
                * This is needed to authenticate the requests that will
    retrieve the content of this URL.
                * */
               URL hrefWithUserInfo =
    URLUtil.attachUserInfo(normalizedUrlInParentRepo, new
    URL(base).getUserInfo(), null, false);

               return new Source() {
                 public void setSystemId(String systemId) {/**/}

                 public String getSystemId() {
                   return hrefWithUserInfo.toExternalForm();
           } catch (URISyntaxException | MalformedURLException e) {/**/}

           return null;

          * Returns a href that is relative to the submodule from the
    parent URL if the given href represents a navigation outside of the
          * @param href An href attribute, which may be relative or
          * @param base The base URI against which the first argument
    will be made absolute if the absolute URI is required.
          * @return A href that is relative to the parent URL (The
    repository that contains submodules).
          * @throws URISyntaxException
         private Optional<String>
    getPathRelativeToSubmoduleInParentRepo(String href, String base)
    throws URISyntaxException {
           Optional<String> relativePathToParentRepo = Optional.empty();

           // If the URL is not inside a submodule there's no need to
    make any change to it.
           if (base != null && href != null /*&&
    urlIsInsideSubmodule.test(base)*/) {

             // If the href is absolute we leave it as is.
             if (!new URI(href).isAbsolute()) {

               String baseUrlWithoutFileName = base.substring(0,
    base.lastIndexOf('/') + 1);

                * ______________ ______ ____________
                * A git URL looks like this:
                * We want to append our relative href to the base git
    URL and normalize it.
                * But we need to add an extra "../" to account for the
    /BRANCH/ part of the git URL.
                * */
               URI normalized = new URI(baseUrlWithoutFileName + "../" +

               String absoluteUrlInsideSubmodule = normalized.toString();
               int upOneLevelIndex =

               // After normalization any "../" left represents a
    navigation outside the current submodule.
               if (upOneLevelIndex != -1) {
                 String hrefRelativeToParent =
                 relativePathToParentRepo =

           return relativePathToParentRepo;

       public void applicationStarted(StandalonePluginWorkspace
    pluginWorkspaceAccess) {
         // Add a URI resolver which will be used to resolve relative
    paths to absolute paths.

         // Add a Relative Reference Resolver which will be used to
    resolve absolute paths to relative paths.
    (baseUrl, childUrl) -> {

           try {
             boolean baseIsInsideAParent =
             boolean childIsInsideAParent =

             if (!baseIsInsideAParent && childIsInsideAParent) {
               // Make the childUrl relative to the baseUrl while taking
    submodules into account.

               String baseUrlString = baseUrl.toExternalForm();
               Matcher matcher =

               if (matcher.find()) {
                 String submoduleUrl =
    baseUrlString.substring(matcher.start(), matcher.end());

                 URL submoduleURL = URLUtil.attachUserInfo(new
    URL(submoduleUrl), baseUrl.getUserInfo(), null, false);

                 // To make this work for all submodules you could have
    a map from a submodule URL to its URL inside the parent.
                 URL submoduleInParentURL = URLUtil.attachUserInfo(new
    URL(submoduleUrlInsideParent), baseUrl.getUserInfo(), null, false);

                 String relativePathToRootOfSubmodule =
    URLUtil.makeRelative(baseUrl, submoduleURL, true, true);
                 if (relativePathToRootOfSubmodule.equals(".")) {
                   relativePathToRootOfSubmodule = "";

                 String relativePathToTargetInsideParent =
    URLUtil.makeRelative(submoduleInParentURL, childUrl, true, true);

                 // Resolved relative URL
                 return relativePathToRootOfSubmodule +

           } catch (MalformedURLException e) { /**/ }

           return null;

       public boolean applicationClosing() {
         return true;

The example.plugin.MyWorkspaceAccessPluginExtension class need to be 
referenced in the plugin.xml file of your plugin [4].

For point 2, you need to add a relative references resolver [5] in 
javascript. This resolver will be used on the client's browser to 
resolve URLs.

    (function () {
       workspace.addRelativeReferencesResolver('gitgle', function
    (baseUrl, childUrl) {

         // Re-implement the java code which was used for

         return "resolvedUrl";

Let us know if you need anything else.



Gabriel Titerlea

On 03-Dec-19 18:48, Jirka Kosek wrote:
> On 3.12.2019 12:40, oXygen XML Editor Support (Gabriel Titerlea) wrote:
>> We're trying to justify a change to the current behavior regarding Git
>> sub-modules in Web Author. Please describe your use-case in more detail.
> It's project where requirements changed over the time ;-)
> Originally separate textbooks have been edited -- each textbook in a
> separate git repository. Each textbook has been standalone. For each
> textbook different group of users has access rights.
> Now requirements changed and some books need to reuse content
> (chapters/section, images, ...) from other books. Merging all individual
> repositories into one large repository (for example using git subtree
> feature) where there will be separate folder for each book is not viable
> as this way we would loose ability to give different access rights for
> different textbooks. Git can set access rights only on whole repository
> not on individual folders inside it.
> So using submodules we can keep textbooks that don't require inclusion
> of assets from other textbooks as they were in a separate repositories.
> Then textbooks that need to reuse content can be edited from "grandrepo"
> that would include all textbooks as submodules.
> Well, yes perhaps this is far beyond what git has been designed for. Git
> was fine for original requirements. Knowing current requirements at the
> start of project would mean that expensive CCMS should be used instead
> of git. :-(
> Thanks and have a nice day,
> 					Jirka

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.oxygenxml.com/pipermail/oxygen-user/attachments/20191206/a4a83491/attachment.html>

More information about the oXygen-user mailing list