// BlogBridge -- RSS feed reader, manager, and web based service // Copyright (C) 2002-2006 by R. Pito Salas // // This program is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free Software Foundation; // either version 2 of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along with this program; // if not, write to the Free Software Foundation, Inc., 59 Temple Place, // Suite 330, Boston, MA 02111-1307 USA // // Contact: R. Pito Salas // mailto:pitosalas@users.sourceforge.net // More information: about BlogBridge // http://www.blogbridge.com // http://sourceforge.net/projects/blogbridge // // $Id: AbstractStressScript.java,v 1.19 2006/01/27 15:23:24 spyromus Exp $ // package com.salas.bb.stresstest.scripts; import com.salas.bb.domain.prefs.UserPreferences; import com.salas.bb.core.GuideModel; import com.salas.bb.core.GlobalController; import com.salas.bb.core.GlobalModel; import com.salas.bb.domain.*; import com.salas.bb.utils.uif.UifUtilities; import com.salas.bb.views.INavigationModes; import com.salas.bb.views.feeds.IFeedDisplay; import com.salas.bb.views.mainframe.FeedsPanel; import javax.swing.*; import java.awt.*; import java.awt.event.KeyEvent; import java.util.regex.Pattern; /** * Abstract implementation of <code>IStressScript</code> with some cool tools. */ public abstract class AbstractStressScript implements IStressScript { private static final Pattern PAT_RANDOM = Pattern.compile("\\$\\{rnd\\}"); private static final Pattern PAT_ITEMS = Pattern.compile("\\$\\{items\\}"); /** * Pre-run initialization. */ public final void init() { childInit(); try { Thread.sleep(3000); } catch (InterruptedException e) { } } /** * Pre-run initialization. */ protected abstract void childInit(); // --------------------------------------------------------------------------------------------- // System Properties Tools // --------------------------------------------------------------------------------------------- /** * Returns integer system property property. * * @param key key. * @param def default value. * * @return value. */ protected static int getIntSystemProperty(String key, int def) { int value = def; String valueStr = System.getProperty(key); try { if (valueStr != null) value = Integer.parseInt(valueStr); } catch (NumberFormatException e) { } return value; } /** * Returns the value of system property. * * @param key key of the property. * @param def default value. * * @return value. */ protected String getSystemProperty(String key, String def) { String value = def; String val = System.getProperty(key); if (val != null) value = val; return value; } // --------------------------------------------------------------------------------------------- // Fast Access To Objects // --------------------------------------------------------------------------------------------- /** * Returns user preferences. * * @return user preferences. */ protected UserPreferences getUserPreferences() { return getModel().getUserPreferences(); } /** * Returns active guide set. * * @return active guide set. */ protected GuidesSet getGuidesSet() { return getModel().getGuidesSet(); } /** * Returns active channel guide model. * * @return active channel guide model. */ protected GuideModel getGuideModel() { return getModel().getGuideModel(); } /** * Returns current model. * * @return current model. */ protected GlobalModel getModel() { return getController().getModel(); } /** * Returns current article list. * * @return current article list. */ protected IFeedDisplay getArticleList() { return null; //getController().getMainFrame().getArticlesListPanel().getArticleList(); } /** * Returns current channel list. * * @return current channel list. */ protected JList getChannelList() { return getChannelListPanel().getFeedsList(); } /** * Returns channel list panel. * * @return channel list panel. */ protected FeedsPanel getChannelListPanel() { return getController().getMainFrame().getFeedsPanel(); } /** * Returns current controller. * * @return current controller. */ protected GlobalController getController() { return GlobalController.SINGLETON; } // --------------------------------------------------------------------------------------------- // Common Actions // --------------------------------------------------------------------------------------------- /** * Sets the parameters of cleanup. * * @param period period in minutes. * @param maxArticles maximum articles in feed to leave. */ protected void setCleanupParameters(int period, int maxArticles) { UserPreferences prefs = getUserPreferences(); prefs.setAutoPurgeIntervalMinutes(period); prefs.setPurgeCount(maxArticles); } /** * Removes all guides. */ protected void removeGuides() { GuidesSet set = getGuidesSet(); set.clear(); } /** * Removes guide from current guides set. * * @param aGuide guide. */ protected void removeGuide(final IGuide aGuide) { if (UifUtilities.isEDT()) { removeGuide0(aGuide); } else { try { SwingUtilities.invokeAndWait(new Runnable() { public void run() { removeGuide0(aGuide); } }); } catch (Exception e) { throw new StressScriptException("Couldn't remove guide.", e); } } } /** * Removes guide from current guides set. * * @param aGuide guide. * * @edt */ private void removeGuide0(IGuide aGuide) { GuidesSet set = getGuidesSet(); set.remove(aGuide); } /** * Creates given number of guides. * * @param guides number of guides to create. */ protected void createGuides(final int guides) { for (int i = 0; i < guides; i++) { createGuide(Integer.toString(i)); } } /** * Creates guide with a given title. * * @param title title of the guide. */ protected void createGuide(final String title) { if (UifUtilities.isEDT()) { createGuide0(title); } else { try { SwingUtilities.invokeAndWait(new Runnable() { public void run() { createGuide0(title); } }); } catch (Exception e) { throw new StressScriptException("Couldn't create guide.", e); } } } /** * Creates single guide. * * @param title title of the guide. * * @edt */ private void createGuide0(String title) { getController().createStandardGuide(title, null, false); } /** * Populates each guide from the guides set with <code>feedPerGuide</code> number of feeds. * Feeds are initialized from <code>urlTemplate</code> URL. In the URL <code>{rnd}</code> * is replaced with current feed sequential number, which is unique to current population * session. The <code>{items}</code> is replaced with <code>articlesPerFeed</code> value. * If <code>waitForInit</code> is set then the engine will wait for feeds initialization * (when articles are loaded) once per guide, meaning that it will populate the guide with * feeds and then wait for their complete initialization. * * @param feedsPerGuide number of feeds to create per guide. * @param articlesPerFeed number of articles per feed to generate. * @param urlTemplate template of feed URL. * @param waitForInit TRUE to wait for initialization of all feeds in the guide. */ protected void populateGuides(int feedsPerGuide, int articlesPerFeed, String urlTemplate, boolean waitForInit) { int feedNumber = 0; GuidesSet set = getModel().getGuidesSet(); // synchronized (set) // { int count = set.getGuidesCount(); for (int i = 0; i < count; i++) { populateGuide(set.getGuideAt(i), feedNumber, feedsPerGuide, articlesPerFeed, urlTemplate, waitForInit); feedNumber += feedsPerGuide; } // } } /** * Populates the given guide with <code>feedsPerGuide</code> number of feeds. For detailed * description of options see {@link AbstractStressScript#populateGuides}. * * @param guide guide to populate with feeds. * @param feedNumber first feed sequential number. * @param feedsPerGuide number of feeds to create in the guide. * @param articlesPerFeed number of articles per feed to generate. * @param urlTemplate template of feed URL. * @param waitForInit TRUE to wait for initialization of all feeds in the guide. */ protected void populateGuide(IGuide guide, int feedNumber, int feedsPerGuide, int articlesPerFeed, String urlTemplate, boolean waitForInit) { getController().selectGuideAndFeed(guide); waitForPendingEvents(); DirectFeed[] feeds = new DirectFeed[feedsPerGuide]; for (int i = 0; i < feedsPerGuide; i++) { String feedUrl = expandTemplate(urlTemplate, feedNumber + i, articlesPerFeed); feeds[i] = getController().createDirectFeed(feedUrl, false); } if (waitForInit) { for (int i = 0; i < feeds.length; i++) { DirectFeed feed = feeds[i]; if (!waitForInitialization(feed)) { throw new StressScriptException("Failed to initialize feed " + "with URL: " + feed.getXmlURL()); } } } } /** * Waits for feed initialization; checks every second. * * @param feed feed to wait for. * * @return TRUE if not invalid. */ protected boolean waitForInitialization(DataFeed feed) { while (!feed.isInitialized() && !feed.isInvalid()) { try { Thread.sleep(1000); } catch (InterruptedException e) { } } return !feed.isInvalid(); } /** * Expands URL template by replacing <code>{rnd}</code> and <code>{items}</code> markers with * <code>aRnd</code> and <code>aItems</code>. * * @param urlTemplate template. * @param aRnd <code>{rnd}</code> replacement. * @param aItems <code>{items}</code> replacement. * * @return prepared URL. */ private String expandTemplate(String urlTemplate, int aRnd, int aItems) { String text = urlTemplate; text = PAT_RANDOM.matcher(text).replaceAll(Integer.toString(aRnd)); text = PAT_ITEMS.matcher(text).replaceAll(Integer.toString(aItems)); return text; } /** * Marks all guides as (un)read. * * @param read TRUE if read. */ protected void markAllGuidesRead(boolean read) { getGuidesSet().setRead(read); waitForPendingEvents(); } /** * Waits until all events in EDT queue scheduled by this moment are dispatched. */ protected void waitForPendingEvents() { try { SwingUtilities.invokeAndWait(new Runnable() { public void run() { // Simply do noting } }); } catch (Exception e) { throw new StressScriptException("Couldn't finish waiting for pending events " + "dispatching.", e); } } /** * Merges two guides. * * @param aGuide1 first guide (will be removed). * @param aGuide2 second guide. */ protected void mergeGuides(final StandardGuide aGuide1, final StandardGuide aGuide2) { if (UifUtilities.isEDT()) { getController().mergeGuides(new IGuide[] { aGuide1 }, aGuide2); } else { try { SwingUtilities.invokeAndWait(new Runnable() { public void run() { getController().mergeGuides(new IGuide[] { aGuide1 }, aGuide2); } }); } catch (Exception e) { throw new StressScriptException("Couldn't merge two guides: " + aGuide1 + " and " + aGuide2, e); } } } protected void postKeyPressed(Component source, int key, int modifiers) { if (source == null) return; long when = System.currentTimeMillis(); KeyEvent keyEvent = new KeyEvent(source, KeyEvent.KEY_PRESSED, when, modifiers, key, KeyEvent.CHAR_UNDEFINED); Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(keyEvent); } /** Selects first guide, feed, unread article. */ protected void selectFirstGuideFeedArticle() { selectFirstGuideFeedArticle(INavigationModes.MODE_UNREAD); } protected void selectFirstGuideFeedArticle(final int mode) { GuidesSet set = getGuidesSet(); final IGuide guide = set.getGuideAt(0); try { SwingUtilities.invokeAndWait(new Runnable() { public void run() { getController().selectGuideAndFeed(guide); IFeed firstFeed = (IFeed)getGuideModel().getElementAt(0); getController().selectFeed(firstFeed); getArticleList().selectFirstArticle(mode); } }); } catch (Exception e) { throw new StressScriptException("Couldn't select first feed.", e); } } /** Selects last guide, feed, unread article. */ protected void selectLastGuideFeedArticle() { selectLastGuideFeedArticle(INavigationModes.MODE_UNREAD); } protected void selectLastGuideFeedArticle(final int mode) { GuidesSet set = getGuidesSet(); final IGuide guide = set.getGuideAt(set.getGuidesCount() - 1); try { SwingUtilities.invokeAndWait(new Runnable() { public void run() { getController().selectGuideAndFeed(guide); IFeed lastFeed = (IFeed)getGuideModel().getElementAt(getGuideModel().getSize() - 1); getController().selectFeed(lastFeed); getArticleList().selectLastArticle(mode); } }); } catch (Exception e) { throw new StressScriptException("Could not select last feed.", e); } } protected void checkIfAllGuidesRead() { GuidesSet set = getGuidesSet(); int aGuideCount = set.getGuidesCount(); for (int g = 0; g < aGuideCount; g++) { IGuide guide = set.getGuideAt(g); if (!guide.isRead()) throw new StressScriptException( "Guide " + guide + " still has unread articles."); } } protected void simulateForwardReadingOfAllArticles() { selectFirstGuideFeedArticle(); JComponent panel = null; //getArticleList().getSelectedPanel(); if (panel != null) { panel.requestFocusInWindow(); waitForPendingEvents(); } GuidesSet cgs = getGuidesSet(); int guideCount = cgs.getGuidesCount(); for (int g = 0; g < guideCount; g++) { IGuide guide = getModel().getSelectedGuide(); if (guide == null) return; int feedCount = guide.getFeedsCount(); for (int f = 0; f < feedCount; f++) { IFeed feed = getModel().getSelectedFeed(); if (feed == null) return; while (!feed.isRead()) { postKeyPressed(getArticleList().getComponent(), KeyEvent.VK_SPACE, 0); waitForPendingEvents(); sleep(100); } } } } protected void simulateBackwardReadingOfAllArticles() { selectLastGuideFeedArticle(); JComponent panel = null; //getArticleList().getSelectedPanel(); if (panel != null) { panel.requestFocusInWindow(); waitForPendingEvents(); } GuidesSet cgs = getGuidesSet(); int guideCount = cgs.getGuidesCount(); for (int g = 0; g < guideCount; g++) { IGuide guide = getModel().getSelectedGuide(); if (guide == null) return; int feedCount = guide.getFeedsCount(); for (int f = 0; f < feedCount; f++) { IFeed feed = getModel().getSelectedFeed(); if (feed == null) return; while (feed.getUnreadArticlesCount() > 0) { postKeyPressed(getArticleList().getComponent(), KeyEvent.VK_SPACE, KeyEvent.SHIFT_DOWN_MASK); waitForPendingEvents(); sleep(100); } } } } private void sleep(long millis) { try { Thread.sleep(millis); } catch (InterruptedException e) { } } }