0

java annotation equivalent in zul file

asked 2015-05-21 10:36:30 +0800

gargamel25 gravatar image gargamel25
41 2

updated 2015-05-22 01:32:06 +0800

cor3000 gravatar image cor3000
6280 2 7

Hi all,

I'm working on an application where I can configure pretty much everything.

For example any toolbar can contain a list of buttons(some action has to be executed on click). These buttons are dragged and drooped by a configuration manager. When you click a button it will execute the action it is designed for.

The definition of an action looks like this:

     @UIAction(actionKey=AddCallLogWebAction.ACTION_KEY, contextClass=Account.class, domainContext=DomainContext.ACCOUNT)
  public class AddCallLogWebAction extends AccountWebAction {

    public static final String ACTION_KEY = "add-call-log-web";

    public final static String defaultIcon = "icon?call-log";


    public AddCallLogWebAction() {
        super("Add Call Log", ACTION_KEY, "l");
        setSmallIcon(defaultIcon);
    }

    public void executed(Event event) {
        if (getDataObject() == null){
            ZKUiUtils.showWarningMsg("No Account Open");
        }else{
            ZKUiUtils.openOkCancelDialog(getText(), getIcon(), getPage(), getDataObject(), "600px");
        }
    }

    protected String getPage() {
        return "/pages/account/dialogs/add_call_log.zul";
    }

}

When I need to configure a specific toolbar I can get a list of all the actions using reflections:

Set<Class<?>> uiActionClasses = reflections.getTypesAnnotatedWith(com.company.ui.configuration.annotations.UIAction.class);

and after filtering the classes that can be applied to a specific toolbar by some other attributes I can display the available buttons for that toolbar.

The problem I'm facing now is that I would like something similar for zul files:

So I have a new component which acts like a container in which I can add some portlets. Imagine you need to display a USER. There you can have some components like: user-address, user-company, user-id and so on... these are some zul files(which in the end up included in the USER.zul) but I can't annotate them to obtain the same pattern as for toolbar actions.

So can you give me some ideas on how to approach this problem. I started looking into : http://books.zkoss.org/wiki/ZUML%20Reference/ZUML/Processing%20Instructions Maybe I can add some custom processing instruction.... and then to get all the zul files in web-app and look for the ones which contain this custom proc instruction

but I would like to see some other paths you would have choosen.

Thank you

delete flag offensive retag edit

3 Answers

Sort by ยป oldest newest most voted
0

answered 2015-05-22 02:04:11 +0800

cor3000 gravatar image cor3000
6280 2 7

zul files are just text files without any automatically parsed meta information. So there is no automatic equivalent. Processing instructions are only parsed once the zul file is already located and processed. So you cannot find the zul file based on a PI unless you implement some manual indexing yourself.

how about doing the same using classes and annotations? Have an object that contains the include path and other meta information you need (not sure if I am following you pattern correctly)

  @UIFragment(fragmentKey=UserAddressFragment.FRAGMENT_KEY, 
              contextClass=Address.class, domainContext=DomainContext.USER))
  public class UserAddressFragment extends Fragment {
    public static final String FRAGMENT_KEY = "user-address";
    public String getPath() { 
        return "/WEB-INF/fragments/user/address.zul";
    }
    ...

Then find these classes using the same as aobve and either create <include> components dynamically or call Executions.createComponents(...) for each fragment found. You can do this in the doAfterCompose method, of your AddressComposer.


Second idea: (A little easier)

why not just define the fragments as macro-components and use them directly where you need it?

in user.zul just list the macros (looks almost like a config file)

<window title="user">
   <user-address/>
   <user-company/>
   ...
</window>

You can define the macros in your lang-addon.xml

<component>
    <component-name>user-address</component-name>
    <macro-uri>/WEB-INF/fragments/user/address.zul</macro-uri>
</component>
link publish delete flag offensive edit
0

answered 2015-05-22 10:12:40 +0800

kategor gravatar image kategor
1
http://www.finansowerady....

I have similar problem ;/

link publish delete flag offensive edit

Comments

did you read my answer, something missing there?

cor3000 ( 2015-05-22 10:51:40 +0800 )edit
0

answered 2015-05-25 11:53:14 +0800

gargamel25 gravatar image gargamel25
41 2

updated 2015-05-25 11:58:28 +0800

Hi cor3000,

Thanks for the quick response.

Although I personally would have chosen one of your solutions my requirements were to make the developers job very easy, so to add a metadata in a zul file like:

<?viewDescriptor domainContext="user"?>

was the most simple thing and somehow equivalent to a java annotation. Your solution implies some extra work to do : to add a linked java class to the zul or to add some configuration in lang-addon to define the macro.

So it has been decided to follow the solution with adding some processing instruction to zuls .

The discovery of the zuls is something like this:

public class Factory {

private static final Factory instance = new Factory();
private List<WebViewDescriptor> zuls = new ArrayList<>();
private boolean init = false;
Pattern regex = Pattern.compile("<\\?viewDescriptor.+domainContext=\"(.*)\".*\\?>", Pattern.DOTALL | Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
boolean IS_WINDOWS = System.getProperty("os.name").contains("indow");

public static Factory getInstance() {
    return instance;
}

public synchronized List<WebViewDescriptor> getAvailableZuls() {
    if (!init) {
        try {
            discover();
        } catch (Exception e) {
            Log.error(e, getClass(), "Error initializing web view descriptors");
        }
    }
    return zuls;

}

@SuppressWarnings("unchecked")
public synchronized void discover() throws Exception {

    // webapp including WEB-INF/classes
    String webapp = Sessions.getCurrent().getWebApp().getServletContext().getRealPath("/").replaceAll("\\\\", "\\\\\\\\");
    Collection<File> listFiles = FileUtils.listFiles(new File(webapp), new String[] { "zul" }, true);
    for (File f : listFiles) {

        List<String> lines = Files.readAllLines(Paths.get(f.getAbsolutePath()), StandardCharsets.UTF_8);
        for (String line : lines) {

            Matcher regexMatcher = regex.matcher(line);
            if (regexMatcher.find()) {
                String src = f.getAbsolutePath().replaceFirst(webapp, "").replaceAll("\\\\", "/");
                if (src.startsWith("WEB-INF/classes/web/")) {
                    src = "/~./" + src.replaceFirst("WEB-INF/classes/web/", "");
                } else if (src.startsWith("WEB-INF")) {
                    src = "/" + src;
                }
                String name = src;
                if(src.lastIndexOf("/") != -1) {
                    name = src.substring(src.lastIndexOf("/")+1);
                }


                String domainContextStr = regexMatcher.group(1);
                List<String> domainContextList = new ArrayList<>();
                if(domainContextStr.lastIndexOf(",") == -1) {
                    domainContextList.add(domainContextStr);
                } else {
                    domainContextList.addAll(Arrays.asList(domainContextStr.split(",")));
                }
                zuls.add(new WebViewDescriptor(src, name, domainContextList));
                break;
            }
        }
    }

    // jars WEB-INF/lib/
    //if we also need other folders we need a recursive method while(classLoader.getParent() != null)

    ClassLoader classLoader = getClass().getClassLoader();
    URL[] urls = ((URLClassLoader) classLoader).getURLs();
    for (int i = 0 ; i < urls.length; i++) {

        String filePath = urls[i].getPath();
        filePath = IS_WINDOWS ? filePath.substring(1) : filePath;
        filePath = URLDecoder.decode(filePath, "UTF-8");
        if(filePath.endsWith(".jar")) {
            try (FileSystem fs = FileSystems.newFileSystem(Paths.get(filePath), null)) {
                Iterable<Path> dirs = fs.getRootDirectories();

                for (Path root : dirs) {
                    Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
                        private final PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:*.{zul}");

                        @Override
                        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                            Path name = file.getFileName();
                            if (name != null && matcher.matches(name)) {
                                System.out.println("Searched file was found: " + name + " in " + file.toRealPath().toString());
                                List<String> lines = Files.readAllLines(file, StandardCharsets.UTF_8);
                                for (String line : lines) {

                                    Matcher regexMatcher = regex.matcher(line);
                                    if (regexMatcher.find()) {
                                        String wvdsrc = file.toRealPath().toString();
                                        if (wvdsrc.startsWith("/web/")) {
                                            wvdsrc = "/~./" + wvdsrc.replaceFirst("/web/", "");
                                        } 
                                        String wvdname = wvdsrc;
                                        if(wvdsrc.lastIndexOf("/") != -1) {
                                            wvdname = wvdsrc.substring(wvdsrc.lastIndexOf("/")+1);
                                        }


                                        String domainContextStr = regexMatcher.group(1);
                                        List<String> domainContextList = new ArrayList<>();
                                        if(domainContextStr.lastIndexOf(",") == -1) {
                                            domainContextList.add(domainContextStr);
                                        } else {
                                            domainContextList.addAll(Arrays.asList(domainContextStr.split(",")));
                                        }
                                        zuls.add(new WebViewDescriptor(wvdsrc, wvdname, domainContextList));
                                        break;
                                    }
                                }

                            }
                            return FileVisitResult.CONTINUE;
                        }

                        @Override
                        public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
                            return FileVisitResult.CONTINUE;
                        }

                        @Override
                        public FileVisitResult postVisitDirectory(Path dir, IOException ioe) {
                            return FileVisitResult.CONTINUE;
                        }
                    });
                }

            } catch (Exception ex) {
                Log.warn(ex, getClass(), "Couldn't parse "+ filePath);
            }

        }

    }

    init = true;

}

}

I hope this helps somebody else who needs to find all zuls in the classpath.

The WebViewDescriptor class is:

public class WebViewDescriptor {

private final String src;
private final String name;
private final List<String> domainContext;


public WebViewDescriptor(String src, String name, List<String> domainContext) {
    super();
    this.src = src;
    this.name = name;
    this.domainContext = domainContext;
}

public String getSrc() {
    return src;
}

public String getName() {
    return name;
}

public List<String> getDomainContext() {
    return domainContext;
}



@Override
public String toString() {
    return "WebViewDescriptor [src=" + src + ", name=" + name + ", domainContext=" + domainContext + "]";
}

}

link publish delete flag offensive edit

Comments

thanks for sharing this, I hope it does the magic in a reliable way, and doesn't cost too much time as the project grows. maybe needs a little adjustment when java 9 comes with jigsaw at the horizon ;) (not sure though)

cor3000 ( 2015-05-26 02:36:59 +0800 )edit
Your answer
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!

[hide preview]

Question tools

Follow
1 follower

RSS

Stats

Asked: 2015-05-21 10:36:30 +0800

Seen: 22 times

Last updated: May 25 '15

Support Options
  • Email Support
  • Training
  • Consulting
  • Outsourcing
Learn More