/******************************************************************************* * Copyright (c) 2007 Exadel, Inc. and Red Hat, Inc. * Distributed under license by Red Hat, Inc. All rights reserved. * This program is made available under the terms of the * Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Exadel, Inc. and Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.jboss.tools.jsf.model.helpers; import java.util.*; import org.jboss.tools.common.model.*; import org.jboss.tools.common.model.util.XModelObjectUtil; import org.jboss.tools.jsf.JSFPreference; import org.jboss.tools.jsf.model.*; import org.jboss.tools.jsf.model.helpers.autolayout.JSFItems; import org.jboss.tools.jsf.model.impl.NavigationRuleObjectImpl; import org.jboss.tools.jst.web.model.ReferenceObject; import org.jboss.tools.jst.web.model.helpers.autolayout.AutoLayout; public class JSFProcessHelper implements JSFConstants { private XModelObject process; private static XModelObject TEMPLATE; private XModelObject config; private Map<String,XModelObject> groups = new HashMap<String,XModelObject>(); private Map<String,XModelObject> targets = new HashMap<String,XModelObject>(); private XModelObject[] rules = new XModelObject[0]; public JSFProcessHelper(XModelObject process) { this.process = process; } private XModelObject getTemplate() { if(TEMPLATE == null && process != null) { TEMPLATE = XModelFactory.getDefaultInstance().createModelObject(ENT_PROCESS_GROUP, null); } return TEMPLATE; } public static JSFProcessHelper getHelper(XModelObject process) { return ((FacesProcessImpl)process).getHelper(); } private synchronized void reset() { groups.clear(); targets.clear(); this.config = process.getParent(); } public void restoreRefs() { ((FacesProcessImpl)process).setReference(process.getParent()); } Set<Object> updateLocks = new HashSet<Object>(); public boolean isUpdateLocked() { return updateLocks.size() > 0; } public void addUpdateLock(Object lock) { updateLocks.add(lock); } public void removeUpdateLock(Object lock) { updateLocks.remove(lock); } public void updateProcess() { if(isUpdateLocked()) return; addUpdateLock(this); try { updateProcess0(); } finally { removeUpdateLock(this); } } private void updateProcess0() { reset(); rules = config.getChildByPath(FOLDER_NAVIGATION_RULES).getChildren(); for (int i = 0; i < rules.length; i++) { String fvi = rules[i].getAttributeValue(ATT_FROM_VIEW_ID); if(fvi == null) continue; String pp = getRuleIdentity(rules[i]); XModelObject g = findOrCreateGroup(fvi, pp); groups.put(pp, g); XModelObject[] cs = rules[i].getChildren(); for (int j = 0; j < cs.length; j++) { String tvi = cs[j].getAttributeValue(ATT_TO_VIEW_ID); if(tvi == null) continue; String ppt = NavigationRuleObjectImpl.toNavigationRulePathPart(tvi); targets.put(ppt, getTemplate()); } } for(String s: groups.keySet()) targets.remove(s); removeObsoleteGroups(); createPageGroups(); updateGroups(); updatePages(); } private String getRuleIdentity(XModelObject rule) { String fvi = rule.getAttributeValue(ATT_FROM_VIEW_ID); String pp = NavigationRuleObjectImpl.toNavigationRulePathPart(fvi); if(!isPattern(fvi)) return pp; String index = rule.getAttributeValue("index"); //$NON-NLS-1$ if(index.startsWith("-") || index.equals("0")) return pp; //$NON-NLS-1$ //$NON-NLS-2$ return pp + ":" + index; //$NON-NLS-1$ } public XModelObject findOrCreateGroup(String path, String pp) { if(pp == null) pp = NavigationRuleObjectImpl.toNavigationRulePathPart(path); XModelObject g = process.getChildByPath(pp); if(g == null) { g = process.getModel().createModelObject(ENT_PROCESS_GROUP, null); g.setAttributeValue(ATT_NAME, pp); g.setAttributeValue(ATT_PATH, path); process.addChild(g); } return g; } private void removeObsoleteGroups() { boolean q = "yes".equals(JSFPreference.DO_NOT_CREATE_EMPTY_RULE.getValue()); //$NON-NLS-1$ XModelObject[] ps = process.getChildren(ENT_PROCESS_GROUP); for (int i = 0; i < ps.length; i++) { String path = ps[i].getPathPart(); if(!groups.containsKey(path) && !targets.containsKey(path)) { if(q && "true".equals(ps[i].getAttributeValue("persistent"))) { //$NON-NLS-1$ //$NON-NLS-2$ groups.put(path, ps[i]); } else { ps[i].removeFromParent(); } } } } private void createPageGroups() { String[] paths = (String[])targets.keySet().toArray(new String[0]); for (int i = 0; i < paths.length; i++) { String fvi = NavigationRuleObjectImpl.toFromViewId(paths[i]); XModelObject g = findOrCreateGroup(fvi, paths[i]); targets.put(paths[i], g); } } private void updateGroups() { ReferenceGroupImpl[] gs = (ReferenceGroupImpl[])groups.values().toArray(new ReferenceGroupImpl[0]); for (int i = 0; i < gs.length; i++) { setGroupReferences(rules, gs[i]); updateGroup(gs[i]); } gs = (ReferenceGroupImpl[])targets.values().toArray(new ReferenceGroupImpl[0]); for (int i = 0; i < gs.length; i++) { gs[i].setReference(new XModelObject[0]); updateGroup(gs[i]); } } private void setGroupReferences(XModelObject[] rules, ReferenceGroupImpl group) { String path = group.getPathPart(); ArrayList<XModelObject> list = null; for (int i = 0; i < rules.length; i++) { String pp = getRuleIdentity(rules[i]); if(!path.equals(pp)) continue; if(list == null) list = new ArrayList<XModelObject>(); list.add(rules[i]); } XModelObject[] rs = (list == null) ? new XModelObject[0] : list.toArray(new XModelObject[list.size()]); group.setReference(rs); } private void updateGroup(ReferenceGroupImpl group) { if(group.isUpToDate()) return; group.notifyUpdate(); XModelObject[] rs = group.getReferences(); XModelObject[] is = group.getChildren(ENT_PROCESS_ITEM); for (int i = 0; i < rs.length; i++) { XModelObject item = null; if(i < is.length) { item = is[i]; } else { item = createItem(group, rs[i]); } ReferenceObjectImpl r = (ReferenceObjectImpl)item; r.setReference(rs[i]); updateItem(r); } for (int i = rs.length; i < is.length; i++) is[i].removeFromParent(); } private XModelObject createItem(XModelObject group, XModelObject rule) { XModelObject item = group.getModel().createModelObject(ENT_PROCESS_ITEM, null); item.setAttributeValue(ATT_ID, rule.getPathPart()); item.setAttributeValue(ATT_PATH, rule.getAttributeValue(ATT_FROM_VIEW_ID)); String name = XModelObjectUtil.createNewChildName("item", group); //$NON-NLS-1$ item.setAttributeValue(ATT_NAME, name); group.addChild(item); return item; } private void updateItem(ReferenceObjectImpl item) { if(item.isUpToDate()) return; item.notifyUpdate(); XModelObject rule = item.getReference(); item.setAttributeValue(ATT_ID, rule.getPathPart()); item.setAttributeValue(ATT_PATH, rule.getAttributeValue(ATT_FROM_VIEW_ID)); updateOutputs(item); } private void updateOutputs(ReferenceObjectImpl item) { XModelObject rule = item.getReference(); XModelObject[] cs = rule.getChildren(); XModelObject[] os = item.getChildren(); if(isOutputOrderUpToDate(cs, os)) { updateOutputs_1(item, cs, os); } else { updateOutputs_2(item, cs, os); } } private void updateOutputs_1(ReferenceObjectImpl item, XModelObject[] cases, XModelObject[] outputs) { int c = 0; for (int i = 0; i < cases.length; i++) { XModelObject output = null; if(c < outputs.length) { output = outputs[c]; } else { output = createOutput(item, cases[i]); } ReferenceObjectImpl r = (ReferenceObjectImpl)output; r.setReference(cases[i]); updateOutput(r); ++c; } for (int i = c; i < outputs.length; i++) outputs[i].removeFromParent(); } private void updateOutputs_2(ReferenceObjectImpl item, XModelObject[] cases, XModelObject[] outputs) { Map<String,XModelObject> map = new HashMap<String,XModelObject>(); for (int i = 0; i < outputs.length; i++) { outputs[i].removeFromParent(); map.put(outputs[i].getAttributeValue(ATT_ID), outputs[i]); } for (int i = 0; i < cases.length; i++) { XModelObject output = map.get(cases[i].getPathPart()); if(output == null) { output = createOutput(item, cases[i]); } else { item.addChild(output); } ReferenceObjectImpl r = (ReferenceObjectImpl)output; r.setReference(cases[i]); updateOutput(r); } } private boolean isOutputOrderUpToDate(XModelObject[] cases, XModelObject[] outputs) { for (int i = 0; i < cases.length && i < outputs.length; i++) { ReferenceObject r = (ReferenceObject)outputs[i]; if(r.getReference() == cases[i]) continue; String pp = cases[i].getPathPart(); String id = outputs[i].getAttributeValue(ATT_ID); if(!pp.equals(id)) return false; } return true; } private XModelObject createOutput(XModelObject item, XModelObject rulecase) { XModelObject output = item.getModel().createModelObject(ENT_PROCESS_ITEM_OUTPUT, null); output.setAttributeValue(ATT_ID, rulecase.getPathPart()); output.setAttributeValue(ATT_PATH, rulecase.getAttributeValue(ATT_TO_VIEW_ID)); String name = XModelObjectUtil.createNewChildName("output", item); //$NON-NLS-1$ output.setAttributeValue(ATT_NAME, name); item.addChild(output); return output; } private void updateOutput(ReferenceObjectImpl output) { if(output.isUpToDate()) return; output.notifyUpdate(); XModelObject rulecase = output.getReference(); output.setAttributeValue(ATT_ID, rulecase.getPathPart()); String path = rulecase.getAttributeValue(ATT_TO_VIEW_ID); output.setAttributeValue(ATT_PATH, path); String title = JSFProcessStructureHelper.createItemOutputPresentation(rulecase); output.setAttributeValue("title", title); //$NON-NLS-1$ XModelObject g = findGroupByPath(path); String target = (g == null) ? "" : g.getPathPart(); //$NON-NLS-1$ output.setAttributeValue(ATT_TARGET, target); } private XModelObject findGroupByPath(String path) { return getPage(path); } public void autolayout() { AutoLayout auto = new AutoLayout(); auto.setItems(new JSFItems()); auto.setProcess(process); } public XModelObject getPage(String path) { path = NavigationRuleObjectImpl.toNavigationRulePathPart(path); XModelObject g = (XModelObject)groups.get(path); if(g == null) g = (XModelObject)targets.get(path); return g; } public void updatePages() { JSFPageUpdateManager pu = JSFPageUpdateManager.getInstance(process.getModel()); pu.lock(); XModelObject[] items = process.getChildren(); for (int i = 0; i < items.length; i++) pu.updatePage(this, items[i]); pu.unlock(); } public static boolean isPattern(String path) { return path != null && (path.length() == 0 || path.indexOf('*') >= 0); } }