001    package org.mycore.frontend;
002    
003    import java.io.File;
004    import java.io.IOException;
005    import java.util.HashMap;
006    
007    import org.apache.log4j.Logger;
008    import org.jdom.Document;
009    import org.jdom.Element;
010    import org.jdom.JDOMException;
011    import org.jdom.input.SAXBuilder;
012    import org.jdom.xpath.XPath;
013    import org.mycore.access.MCRAccessInterface;
014    import org.mycore.access.MCRAccessManager;
015    import org.mycore.access.mcrimpl.MCRAccessStore;
016    import org.mycore.common.MCRConfiguration;
017    import org.mycore.common.MCRSessionMgr;
018    import org.mycore.user.MCRUser;
019    
020    public class MCRLayoutUtilities {
021        final static String OBJIDPREFIX_WEBPAGE = "webpage:";
022    
023        final static String READ_PERMISSION_WEBPAGE = "read";
024    
025        // strategies for access verification
026        public final static int ALLTRUE = 1;
027    
028        public final static int ONETRUE_ALLTRUE = 2;
029    
030        public final static int ALL2BLOCKER_TRUE = 3;
031    
032        private final static Logger LOGGER = Logger.getLogger(MCRLayoutUtilities.class);
033    
034        private static HashMap<String, Element> itemStore = new HashMap<String, Element>();
035    
036        private static long CACHE_INITTIME = 0;
037    
038        private static Document NAVI;
039    
040        private static final String NAV_LOC_DEFAULT = MCRConfiguration.instance().getString("MCR.basedir")
041                        + "build/webapps/config/navigation.xml".replace('/', File.separatorChar);
042    
043        private static final File NAVFILE = new File(MCRConfiguration.instance().getString("MCR.navigationFile", NAV_LOC_DEFAULT).replace('/',
044                        File.separatorChar));
045    
046        private static final boolean ACCESS_CONTROLL_ON = MCRConfiguration.instance().getBoolean("MCR.Website.ReadAccessVerification", true);
047    
048        /**
049         * Verifies a given $webpage-ID (//item/@href) from navigation.xml on read
050         * permission, based on ACL-System. To be used by XSL with
051         * Xalan-Java-Extension-Call. $blockerWebpageID can be used as already
052         * verified item with read access. So, only items of the ancestor axis till
053         * and exclusive $blockerWebpageID are verified. Use this, if you want to
054         * speed up the check
055         * 
056         * @param webpageID,
057         *            any item/@href from navigation.xml
058         * @param blockerWebpageID,
059         *            any ancestor item of webpageID from navigation.xml
060         * @return true if access granted, false if not
061         */
062        public static boolean readAccess(String webpageID, String blockerWebpageID) {
063            if (ACCESS_CONTROLL_ON) {
064                long startTime = System.currentTimeMillis();
065                boolean access = getAccess(webpageID, "read", ALL2BLOCKER_TRUE, blockerWebpageID);
066                LOGGER.debug("checked read access for webpageID= " + webpageID + " (with blockerWebpageID =" + blockerWebpageID + ") => " + access + ": took "
067                                + getDuration(startTime) + " msec.");
068                return access;
069            } else
070                return true;
071        }
072    
073        /**
074         * Verifies a given $webpage-ID (//item/@href) from navigation.xml on read
075         * permission, based on ACL-System. To be used by XSL with
076         * Xalan-Java-Extension-Call.
077         * 
078         * @param webpageID,
079         *            any item/@href from navigation.xml
080         * @return true if access granted, false if not
081         */
082        public static boolean readAccess(String webpageID) {
083            if (ACCESS_CONTROLL_ON) {
084                long startTime = System.currentTimeMillis();
085                boolean access = getAccess(webpageID, "read", ALLTRUE);
086                LOGGER.debug("checked read access for webpageID= " + webpageID + " => " + access + ": took " + getDuration(startTime) + " msec.");
087                return access;
088            } else
089                return true;
090        }
091    
092        /**
093         * Returns all labels of the ancestor axis for the given item within
094         * navigation.xml
095         * 
096         * @param itemClone
097         * @return Label as String, like "labelRoot > labelChild >
098         *         labelChildOfChild"
099         * @throws JDOMException
100         * @throws IOException
101         */
102        public static final String getAncestorLabels(Element item) {
103            String label = "";
104            String lang = MCRSessionMgr.getCurrentSession().getCurrentLanguage().trim();
105            XPath xpath;
106            Element ic = null;
107            try {
108                xpath = XPath.newInstance("//.[@href='" + getWebpageID(item) + "']");
109                ic = (Element) xpath.selectSingleNode(getNavi());
110            } catch (JDOMException e) {
111                e.printStackTrace();
112            }
113            while (ic.getName().equals("item")) {
114                ic = ic.getParentElement();
115                String webpageID = getWebpageID(ic);
116                Element labelEl = null;
117                try {
118                    xpath = XPath.newInstance("//.[@href='" + webpageID + "']/label[@xml:lang='" + lang + "']");
119                    labelEl = (Element) xpath.selectSingleNode(getNavi());
120                } catch (JDOMException e) {
121                    e.printStackTrace();
122                }
123                if (labelEl != null) {
124                    if (label.equals(""))
125                        label = labelEl.getTextTrim();
126                    else
127                        label = labelEl.getTextTrim() + " > " + label;
128                }
129            }
130            return label;
131        }
132    
133        /**
134         * Verifies, if an item of navigation.xml has a given $permission.
135         * 
136         * @param webpageID,
137         *            item/@href
138         * @param permission,
139         *            permission to look for
140         * @param strategy:
141         *            ALLTRUE => all ancestor items of webpageID must have the
142         *            permission, ONETRUE_ALLTRUE => only 1 ancestor item must have
143         *            the permission
144         * @return true, if access, false if no access
145         */
146        public static boolean getAccess(String webpageID, String permission, int strategy) {
147            Element item = getItem(webpageID);
148            // check permission according to $strategy
149            boolean access = false;
150            if (strategy == ALLTRUE) {
151                access = true;
152                do {
153                    access = itemAccess(permission, item, access);
154                    item = item.getParentElement();
155                } while (item != null && access);
156            } else if (strategy == ONETRUE_ALLTRUE) {
157                access = false;
158                do {
159                    access = itemAccess(permission, item, access);
160                    item = item.getParentElement();
161                } while (item != null && !access);
162            }
163            return access;
164        }
165    
166        /**
167         * Verifies, if an item of navigation.xml has a given $permission with a
168         * stop item ($blockerWebpageID)
169         * 
170         * @param webpageID,
171         *            item/@href
172         * @param permission,
173         *            permission to look for
174         * @param strategy:
175         *            ALL2BLOCKER_TRUE => all ancestor items of webpageID till and
176         *            exlusiv $blockerWebpageID must have the permission
177         * @param blockerWebpageID:
178         *            any ancestor item of webpageID from navigation.xml
179         * @return true, if access, false if no access
180         */
181        public static boolean getAccess(String webpageID, String permission, int strategy, String blockerWebpageID) {
182            Element item = getItem(webpageID);
183            // check permission according to $strategy
184            boolean access = false;
185            if (strategy == ALL2BLOCKER_TRUE) {
186                access = true;
187                do {
188                    access = itemAccess(permission, item, access);
189                    item = item.getParentElement();
190                } while (item != null && access && !getWebpageID(item).equals(blockerWebpageID));
191            }
192            return access;
193        }
194    
195        /**
196         * Returns a Element presentation of an item[@href=$webpageID]
197         * 
198         * @param webpageID
199         * @return Element
200         */
201        private static Element getItem(String webpageID) {
202            if (!naviCacheValid())
203                itemStore.clear();
204            Element item = itemStore.get(webpageID);
205            if (item == null) {
206                XPath xpath;
207                try {
208                    xpath = XPath.newInstance("//.[@href='" + webpageID + "']");
209                    item = (Element) xpath.selectSingleNode(getNavi());
210                } catch (JDOMException e) {
211                    e.printStackTrace();
212                }
213                itemStore.put(webpageID, item);
214            }
215            return item;
216        }
217    
218        /**
219         * Verifies a single item on access according to $permission
220         * 
221         * @param permission
222         * @param item
223         * @param access,
224         *            initial value
225         * @return
226         */
227        public static boolean itemAccess(String permission, Element item, boolean access) {
228            String objID = getWebpageACLID(item);
229            if (MCRAccessManager.hasRule(objID, permission))
230                access = MCRAccessManager.checkPermission(objID, permission);
231            return access;
232        }
233    
234        /**
235         * Verifies a single item on access according to $permission and for a given
236         * user
237         * 
238         * @param permission
239         * @param item
240         * @param access,
241         *            initial value
242         * @param user
243         * @return
244         */
245        public static boolean itemAccess(String permission, Element item, boolean access, MCRUser user) {
246            MCRAccessInterface am = MCRAccessManager.getAccessImpl();
247            String objID = getWebpageACLID(item);
248            if (am.hasRule(objID, permission))
249                access = am.checkPermission(objID, permission, user);
250            return access;
251        }
252    
253        /**
254         * Verifies if the cache of navigation.xml is valid.
255         * 
256         * @return true if valid, false if note
257         */
258        private static boolean naviCacheValid() {
259            if (CACHE_INITTIME < NAVFILE.lastModified())
260                return false;
261            else
262                return true;
263        }
264    
265        private static String getWebpageACLID(Element item) {
266            return OBJIDPREFIX_WEBPAGE + getWebpageID(item);
267        }
268    
269        public static String getWebpageACLID(String webpageID) {
270            return OBJIDPREFIX_WEBPAGE + webpageID;
271        }
272    
273        private static String getWebpageID(Element item) {
274            return item.getAttributeValue("href");
275        }
276    
277        /**
278         * Returns the navigation.xml as org.jdom.document, using a cache the
279         * enhance loading time.
280         * 
281         * @return navigation.xml as org.jdom.document
282         */
283        public static Document getNavi() {
284            if (!naviCacheValid()) {
285                try {
286                    NAVI = new SAXBuilder().build(NAVFILE);
287                } catch (JDOMException e) {
288                    e.printStackTrace();
289                } catch (IOException e) {
290                    e.printStackTrace();
291                }
292                CACHE_INITTIME = System.currentTimeMillis();
293            }
294            return NAVI;
295        }
296    
297        public static long getDuration(long startTime) {
298            return (System.currentTimeMillis() - startTime);
299        }
300    
301        public static String getOBJIDPREFIX_WEBPAGE() {
302            return OBJIDPREFIX_WEBPAGE;
303        }
304    
305        public static boolean hasRule(String permission, String webpageID) {
306            MCRAccessInterface am = MCRAccessManager.getAccessImpl();
307            return am.hasRule(getWebpageACLID(webpageID), permission);
308        }
309    
310        public static String getRuleID(String permission, String webpageID) {
311            MCRAccessStore as = MCRAccessStore.getInstance();
312            String ruleID = as.getRuleID(getWebpageACLID(webpageID), permission);
313            if (ruleID != null)
314                return ruleID;
315            else
316                return "";
317        }
318    
319        public static String getRuleDescr(String permission, String webpageID) {
320            MCRAccessInterface am = MCRAccessManager.getAccessImpl();
321            String ruleDes = am.getRuleDescription(getWebpageACLID(webpageID), permission);
322            if (ruleDes != null)
323                return ruleDes;
324            else
325                return "";
326        }
327    
328        public static String getPermission2ReadWebpage() {
329            return READ_PERMISSION_WEBPAGE;
330        }
331    
332        public static String getLastValidPageID() {
333            String page = (String) MCRSessionMgr.getCurrentSession().get("lastPageID");
334            return (page == null ? "" : page);
335        }
336    
337        public static String setLastValidPageID(String pageID) {
338            MCRSessionMgr.getCurrentSession().put("lastPageID", pageID);
339            return "";
340        }
341    }