Example usage for org.apache.commons.digester3 Digester push

List of usage examples for org.apache.commons.digester3 Digester push

Introduction

In this page you can find the example usage for org.apache.commons.digester3 Digester push.

Prototype

public <T> void push(T object) 

Source Link

Document

Push a new object onto the top of the object stack.

Usage

From source file:eu.scape_project.planning.services.pa.PreservationActionRegistryFactory.java

static public List<PreservationActionRegistryDefinition> getAvailableRegistries()
        throws PlanningServiceException {
    ArrayList<PreservationActionRegistryDefinition> allRegistries = new ArrayList<PreservationActionRegistryDefinition>();

    String configFile = "data/services/PreservationActionRegistries.xml";
    InputStream config = Thread.currentThread().getContextClassLoader().getResourceAsStream(configFile);

    if (config == null) {
        throw new PlanningServiceException("Config file not found: " + configFile);
    }/*from   ww w  .ja va  2 s .  c  o  m*/

    Digester digester = new Digester();
    digester.setValidating(false);
    digester.setErrorHandler(new StrictErrorHandler());

    digester.push(allRegistries);
    digester.addObjectCreate("*/registry", PreservationActionRegistryDefinition.class);
    digester.addBeanPropertySetter("*/registry/shortname", "shortname");
    digester.addBeanPropertySetter("*/registry/logo", "logo");
    digester.addBeanPropertySetter("*/registry/url", "url");
    digester.addBeanPropertySetter("*/registry/type", "type");
    digester.addBeanPropertySetter("*/registry/active", "active");
    digester.addSetNext("*/registry", "add");

    try {
        digester.setUseContextClassLoader(true);
        digester.parse(config);
    } catch (Exception e) {
        throw new PlanningServiceException(e);
    }
    return allRegistries;
}

From source file:com.thoughtworks.go.plugin.infra.plugininfo.GoPluginDescriptorParser.java

public static GoPluginDescriptor parseXML(InputStream pluginXML, String pluginJarFileLocation,
        File pluginBundleLocation, boolean isBundledPlugin) throws IOException, SAXException {
    Digester digester = initDigester();
    GoPluginDescriptorParser parserForThisXML = new GoPluginDescriptorParser(pluginJarFileLocation,
            pluginBundleLocation, isBundledPlugin);
    digester.push(parserForThisXML);

    digester.addCallMethod("go-plugin", "createPlugin", 2);
    digester.addCallParam("go-plugin", 0, "id");
    digester.addCallParam("go-plugin", 1, "version");

    digester.addCallMethod("go-plugin/about", "createAbout", 4);
    digester.addCallParam("go-plugin/about/name", 0);
    digester.addCallParam("go-plugin/about/version", 1);
    digester.addCallParam("go-plugin/about/target-go-version", 2);
    digester.addCallParam("go-plugin/about/description", 3);

    digester.addCallMethod("go-plugin/about/vendor", "createVendor", 2);
    digester.addCallParam("go-plugin/about/vendor/name", 0);
    digester.addCallParam("go-plugin/about/vendor/url", 1);

    digester.addCallMethod("go-plugin/about/target-os/value", "addTargetOS", 1);
    digester.addCallParam("go-plugin/about/target-os/value", 0);

    digester.parse(pluginXML);/*from w w  w . j a  va2 s. c o  m*/

    return parserForThisXML.descriptor;
}

From source file:br.univali.celine.lms.config.LMSConfig.java

private static void doBuildConfig(String path) throws Exception {

    Digester d = new Digester();
    d.setUseContextClassLoader(true);//from   w w  w  . j  a v a  2  s .  c om
    d.push(config);

    d.addCallMethod("*/courses-folder", "setCoursesFolder", 0);
    //        d.addCallMethod("*/login-page", "setLoginPage", 0);
    d.addCallMethod("*/registerCourseOnImport", "setRegisterCourseOnImport", 0);
    d.addCallMethod("*/registerUserOnInsertCourse", "setRegisterUserOnInsert", 0);
    d.addCallMethod("*/error-page", "setErrorPage", 0);
    d.addCallMethod("*/lmsIntegration", "setLMSIntegration", 0);

    d.addObjectCreate("*/database-source/rdb", RDBDAO.class);
    d.addSetNestedProperties("*/database-source/rdb");
    d.addSetNext("*/database-source/rdb", "setDAO");

    d.addObjectCreate("*/database-source/xml", XMLDAO.class);
    d.addCallMethod("*/database-source/xml", "setFileName", 0);
    d.addSetNext("*/database-source/xml", "setDAO");

    d.addObjectCreate("*/database-source/bean", "", "class"); // devido a um bug da versao 3.3 tive que fazer esse workaround !!!
    //d.addObjectCreate("*/database-source/bean", "class", DAO.class); 
    d.addSetNext("*/database-source/bean", "setDAO");

    d.addRule("*/database-source/bean/bean-attribute", new BeanSetterAttribute());

    String fileName = path + "/celine-config.xml";
    java.io.File srcfile = new java.io.File(fileName);
    d.parse(srcfile);

    if (config.dao == null)
        throw new Exception("DAO is not defined at celine-config.xml");

    config.dao.initialize();

}

From source file:architecture.ee.web.navigator.XmlMenuHolder.java

protected Digester initDigester() {

    Digester digester = new Digester();
    digester.setClassLoader(Thread.currentThread().getContextClassLoader());
    digester.push(this);

    // 1//from   ww  w .  j  av a 2  s .  co m
    digester.addObjectCreate("MenuConfig/Menus/Menu", "architecture.ee.web.navigator.MenuComponent", "type");
    digester.addSetProperties("MenuConfig/Menus/Menu");
    digester.addSetNext("MenuConfig/Menus/Menu", "addMenu");

    // 2
    digester.addObjectCreate("MenuConfig/Menus/Menu/Item", "architecture.ee.web.navigator.MenuComponent",
            "type");
    digester.addSetProperties("MenuConfig/Menus/Menu/Item");
    digester.addSetNext("MenuConfig/Menus/Menu/Item", "addMenuComponent",
            "architecture.ee.web.navigator.MenuComponent");

    // 3        
    digester.addObjectCreate("MenuConfig/Menus/Menu/Item/Item", "architecture.ee.web.navigator.MenuComponent",
            "type");
    digester.addSetProperties("MenuConfig/Menus/Menu/Item/Item");
    digester.addSetNext("MenuConfig/Menus/Menu/Item/Item", "addMenuComponent",
            "architecture.ee.web.navigator.MenuComponent");

    // 4
    digester.addObjectCreate("MenuConfig/Menus/Menu/Item/Item/Item",
            "architecture.ee.web.navigator.MenuComponent", "type");
    digester.addSetProperties("MenuConfig/Menus/Menu/Item/Item/Item");
    digester.addSetNext("MenuConfig/Menus/Menu/Item/Item/Item", "addMenuComponent",
            "architecture.ee.web.navigator.MenuComponent");

    // 5
    digester.addObjectCreate("MenuConfig/Menus/Menu/Item/Item/Item/Item",
            "architecture.ee.web.navigator.MenuComponent", "type");
    digester.addSetProperties("MenuConfig/Menus/Menu/Item/Item/Item/Item");
    digester.addSetNext("MenuConfig/Menus/Menu/Item/Item/Item/Item", "addMenuComponent",
            "architecture.ee.web.navigator.MenuComponent");

    // 6
    digester.addObjectCreate("MenuConfig/Menus/Menu/Item/Item/Item/Item/Item",
            "architecture.ee.web.navigator.MenuComponent", "type");
    digester.addSetProperties("MenuConfig/Menus/Menu/Item/Item/Item/Item/Item");
    digester.addSetNext("MenuConfig/Menus/Menu/Item/Item/Item/Item/Item", "addMenuComponent",
            "architecture.ee.web.navigator.MenuComponent");

    // 7
    digester.addObjectCreate("MenuConfig/Menus/Menu/Item/Item/Item/Item/Item/Item",
            "architecture.ee.web.navigator.MenuComponent", "type");
    digester.addSetProperties("MenuConfig/Menus/Menu/Item/Item/Item/Item/Item/Item");
    digester.addSetNext("MenuConfig/Menus/Menu/Item/Item/Item/Item/Item/Item", "addMenuComponent",
            "architecture.ee.web.navigator.MenuComponent");

    /**
    digester.addObjectCreate("MenuConfig/Displayers/Displayer", "net.sf.navigator.displayer.MenuDisplayerMapping", "mapping");
    digester.addSetProperties("MenuConfig/Displayers/Displayer");
    digester.addSetNext("MenuConfig/Displayers/Displayer", "addMenuDisplayerMapping", "net.sf.navigator.displayer.MenuDisplayerMapping");
    digester.addSetProperty("MenuConfig/Displayers/Displayer/SetProperty", "property", "value");
    */

    return digester;
}

From source file:eu.scape_project.planning.xml.TreeLoader.java

private MindMap loadFreeMindMap(InputStream in) {
    try {//from   w ww . j a  va2s  .co  m
        MindMap map = new MindMap();
        SAXParserFactory f = SAXParserFactory.newInstance();
        SAXParser parser = f.newSAXParser();

        //            SAXParser parser = validatingParserFactory.getValidatingParser();
        //            parser.setProperty(ValidatingParserFactory.JAXP_SCHEMA_SOURCE,
        //                "http://freemind.sourceforge.net/freemind.xsd");
        // load content into temporary structure
        Digester digester = new Digester(parser);
        //            digester.setEntityResolver(new SchemaResolver().addSchemaLocation(
        //                "http://freemind.sourceforge.net/freemind.xsd", "data/schemas/freemind.xsd"));
        //            digester.setErrorHandler(new StrictErrorHandler());

        digester.push(map);

        digester.addObjectCreate("*/node", "eu.scape_project.planning.xml.freemind.Node");
        digester.addSetProperties("*/node");
        digester.addCallMethod("*/node/hook/text", "setDESCRIPTION", 0);
        digester.addSetNext("*/node", "addChild");

        digester.setUseContextClassLoader(true);
        digester.parse(in);
        return map;
    } catch (IOException e) {
        log.error("Error loading Freemind file.", e);
    } catch (SAXException e) {
        log.error("Document is not a valid Freemind file.", e);
    } catch (ParserConfigurationException e) {
        log.error("Parser not properly configured.", e);
    }
    return null;
}

From source file:eu.scape_project.planning.xml.PlanMigrator.java

/**
 * Detect the version of the given XML representation of plans. If the
 * version of the XML representation is not up to date, necessary
 * transformations are applied./*w  ww.j a v  a  2s .  co m*/
 * 
 * @param importData
 * @return null if the transformation fails, otherwise an up to date XML
 *         representation
 * @throws IOException
 *             if parsing the XML representation fails
 * @throws SAXException
 *             if parsing the XML representation fails
 */
public String getCurrentVersionData(final InputStream in, final String tempPath,
        final List<String> appliedTransformations) throws PlatoException {
    String originalFile = tempPath + "_original.xml";
    try {
        FileUtils.writeToFile(in, new FileOutputStream(originalFile));

        /** check for the version of the file **/

        // The version of the read xml file is unknown, so it is not possible to
        // validate it
        // moreover, in old plans the version attribute was on different
        // nodes(project, projects),
        // with a different name (fileVersion)
        // to be backwards compatible we create rules for all these attributes
        fileVersion = "xxx";
        SAXParserFactory factory = SAXParserFactory.newInstance();
        factory.setNamespaceAware(false);
        Digester d = new Digester(factory.newSAXParser());

        d.setValidating(false);
        // StrictErrorHandler errorHandler = new StrictErrorHandler();
        // d.setErrorHandler(errorHandler);
        d.push(this);
        // to read the version we have to support all versions:
        d.addSetProperties("*/projects", "version", "fileVersion");
        // manually migrated projects may have the file version in the node
        // projects/project
        d.addSetProperties("*/projects/project", "version", "fileVersion");
        // pre V1.3 version info was stored in the project node
        d.addSetProperties("*/project", "version", "fileVersion");
        // since V1.9 the root node is plans:
        d.addSetProperties("plans", "version", "fileVersion");

        InputStream inV = new FileInputStream(originalFile);
        d.parse(inV);
        inV.close();
        /** this could be more sophisticated, but for now this is enough **/
        String version = "1.0";
        if (fileVersion != null) {
            version = fileVersion;
        }

        String fileTo = originalFile;
        String fileFrom = originalFile;

        boolean success = true;
        if ("xxx".equals(version)) {
            fileFrom = fileTo;
            fileTo = fileFrom + "_V1.3.xml";
            /** this is an old export file, transform it to the 1.3 schema **/
            success = transformXmlData(fileFrom, fileTo, "data/xslt/Vxxx-to-V1.3.xsl");
            appliedTransformations.add("Vxxx-to-V1.3.xsl");
            version = "1.3";
        }
        if (success && "1.3".equals(version)) {
            fileFrom = fileTo;
            fileTo = fileFrom + "_V1.9.xml";
            success = transformXmlData(fileFrom, fileTo, "data/xslt/V1.3-to-V1.9.xsl");
            appliedTransformations.add("V1.3-to-V1.9.xsl");
            version = "1.9";
        }
        // with release of Plato 2.0 and its schema ProjectExporter creates
        // documents with version 2.0
        if (success && "1.9".equals(version)) {
            version = "2.0";
        }
        if (success && "2.0".equals(version)) {
            // transform the document to version 2.1
            fileFrom = fileTo;
            fileTo = fileFrom + "_V2.1.xml";
            success = transformXmlData(fileFrom, fileTo, "data/xslt/V2.0-to-V2.1.xsl");
            appliedTransformations.add("V2.0-to-V2.1.xsl");
            version = "2.1";
        }
        if (success && "2.1".equals(version)) {
            // transform the document to version 2.1.2
            fileFrom = fileTo;
            fileTo = fileFrom + "_V2.1.2.xml";
            success = transformXmlData(fileFrom, fileTo, "data/xslt/V2.1-to-V2.1.2.xsl");
            appliedTransformations.add("V2.1-to-V2.1.2.xsl");
            version = "2.1.2";
        }
        if (success && "2.1.1".equals(version)) {
            // transform the document to version 2.1.2
            fileFrom = fileTo;
            fileTo = fileFrom + "_V2.1.2.xml";
            success = transformXmlData(fileFrom, fileTo, "data/xslt/V2.1.1-to-V2.1.2.xsl");
            appliedTransformations.add("V2.1.1-to-V2.1.2.xsl");
            version = "2.1.2";
        }

        if (success && "2.1.2".equals(version)) {
            // transform the document to version 3.0.0
            fileFrom = fileTo;
            fileTo = fileFrom + "_V3.0.0.xml";
            success = transformXmlData(fileFrom, fileTo, "data/xslt/V2.1.2-to-V3.0.0.xsl");
            appliedTransformations.add("V2.1.2-to-V3.0.0.xsl");
            version = "3.0.0";
        }
        if (success && "3.0.0".equals(version)) {
            // transform the document to version 3.0.1
            fileFrom = fileTo;
            fileTo = fileFrom + "_V3.0.1.xml";
            success = transformXmlData(fileFrom, fileTo, "data/xslt/V3.0.0-to-V3.0.1.xsl");
            appliedTransformations.add("V3.0.0-to-V3.0.1.xsl");
            version = "3.0.1";
        }
        if (success && "3.0.1".equals(version)) {
            // transform the document to version 3.9.0
            fileFrom = fileTo;
            fileTo = fileFrom + "_V3.9.0.xml";
            success = transformXmlData(fileFrom, fileTo, "data/xslt/V3.0.1-to-V3.9.0.xsl");
            appliedTransformations.add("V3.0.1-to-V3.9.0.xsl");
            version = "3.9.0";
        }
        if (success && "3.9.0".equals(version)) {
            // transform the document to version 3.9.9
            fileFrom = fileTo;
            fileTo = fileFrom + "_V3.9.9.xml";
            success = transformXmlData(fileFrom, fileTo, "data/xslt/V3.9.0-to-V3.9.9.xsl");
            appliedTransformations.add("V3.9.0-to-V3.9.9.xsl");
            version = "3.9.9";
        }
        if (success && "3.9.9".equals(version)) {
            // transform the document to version 4.0.0
            fileFrom = fileTo;
            fileTo = fileFrom + "_V4.0.1.xml";
            success = transformXmlData(fileFrom, fileTo, "data/xslt/V3.9.9-to-V4.0.1.xsl");
            appliedTransformations.add("V3.9.9-to-V4.0.1.xsl");
            version = "4.0.1";
        }
        if (success && "4.0.1".equals(version)) {
            // transform the document to version 4.0.0
            fileFrom = fileTo;
            fileTo = fileFrom + "_V4.0.2.xml";
            success = transformXmlData(fileFrom, fileTo, "data/xslt/V4.0.1-to-V4.0.2.xsl");
            appliedTransformations.add("V4.0.1-to-V4.0.2.xsl");
            version = "4.0.2";
        }

        if (success) {
            return fileTo;
        } else {
            return null;
        }
    } catch (Exception e) {
        throw new PlatoException("Failed to update plan to current version.", e);
    }
}

From source file:br.univali.celine.scorm.model.cam.ContentPackageReader20043rd.java

public ContentPackage read(java.io.InputStream stream) throws Exception {
    // Create a Digester instance
    Digester d = new Digester();
    d.setNamespaceAware(true); // desconsidera todos os namespaces !!!

    // Prime the digester stack with an object for rules to
    // operate on. Note that it is quite common for "this"
    // to be the object pushed.
    ContentPackage manifest = new ContentPackage(this);
    d.push(manifest);
    // Add rules to the digester that will be triggered while
    // parsing occurs.
    addRules(d);// w  w  w. j  a v a2s.  c om

    // Process the input file.
    d.parse(stream);

    manifest.finalization();

    return manifest;
}

From source file:eu.scape_project.planning.xml.PlanParser.java

/**
 * Imports the XML representation of templates.
 * // w w  w  .  j  av  a  2  s  .  c  o m
 * @param in
 *            the input stream to read from
 * @return a list of read templates.
 * @throws PlatoException
 *             if the template cannot be parsed
 */
public List<TemplateTree> importTemplates(final InputStream in) throws PlatoException {

    try {
        Digester digester = new Digester();
        // digester.setValidating(true);
        StrictErrorHandler errorHandler = new StrictErrorHandler();
        digester.setErrorHandler(errorHandler);

        // At the moment XML files for template tree's are only used
        // internally,
        // later we will define a schema and use it also for validation

        digester.push(this);

        digester.addObjectCreate("*/template", TemplateTree.class);
        digester.addSetProperties("*/template");
        digester.addSetRoot("*/template", "setTemplate");
        // digester.addSetNext("*/template/name", "setName");
        // digester.addSetNext("*/template/owner", "setOwner");

        PlanParser.addTreeParsingRulesToDigester(digester);

        digester.addObjectCreate("*/template/node", Node.class);
        digester.addSetProperties("*/template/node");
        digester.addSetNext("*/template/node", "addChild");

        digester.setUseContextClassLoader(true);

        templates = new ArrayList<TemplateTree>();
        digester.parse(in);
        // FIXME:
        /*
         * for (TemplateTree t : templates) { log.info(t.getName() +
         * t.getOwner()); }
         */

        return templates;
    } catch (Exception e) {
        throw new PlatoException("Failed to parse template tree.", e);
    }
}

From source file:eu.scape_project.planning.xml.PlanParser.java

/**
 * Imports the XML representation of plans from the given input stream.
 * /*  w  w  w.  ja v  a  2  s.c  o m*/
 * @param in
 *            the input stream to read from
 * @return list of read plans
 * @throws PlatoException
 *             if the plan cannot be parsed
 */
public List<Plan> importProjects(final InputStream in) throws PlatoException {
    try {

        SAXParser parser = validatingParserFactory.getValidatingParser();
        parser.setProperty(ValidatingParserFactory.JAXP_SCHEMA_SOURCE, PlanXMLConstants.PLAN_SCHEMAS);

        Digester digester = new Digester(parser);

        SchemaResolver schemaResolver = new SchemaResolver();

        schemaResolver
                .addSchemaLocation(PlanXMLConstants.PLATO_SCHEMA_URI, PlanXMLConstants.PLATO_SCHEMA_LOCATION)
                .addSchemaLocation(PlanXMLConstants.PAP_SCHEMA_URI, PlanXMLConstants.PAP_SCHEMA_LOCATION)
                .addSchemaLocation(PlanXMLConstants.TAVERNA_SCHEMA_URI,
                        PlanXMLConstants.TAVERNA_SCHEMA_LOCATION);

        digester.setEntityResolver(schemaResolver);
        digester.setErrorHandler(new StrictErrorHandler());
        digester.setNamespaceAware(true);
        digester.push(this);

        PlanParser.addRules(digester);

        digester.setUseContextClassLoader(true);
        plans = new ArrayList<Plan>();

        // finally parse the XML representation with all created rules
        digester.parse(in);

        for (Plan plan : plans) {
            String projectName = plan.getPlanProperties().getName();
            if ((projectName != null) && (!"".equals(projectName))) {
                /*
                 * establish links from values to scales. For all(!)
                 * alternatives: An alternative could have be discarded
                 * after some measurements have already been added.
                 */
                plan.getTree().initValues(plan.getAlternativesDefinition().getAlternatives(),
                        plan.getSampleRecordsDefinition().getRecords().size(), true);
                /*
                 * establish references of Experiment.uploads
                 */
                HashMap<String, SampleObject> records = new HashMap<String, SampleObject>();
                for (SampleObject record : plan.getSampleRecordsDefinition().getRecords()) {
                    records.put(record.getShortName(), record);
                }
                for (Alternative alt : plan.getAlternativesDefinition().getAlternatives()) {
                    if ((alt.getExperiment() != null) && (alt.getExperiment() instanceof ExperimentWrapper)) {
                        alt.setExperiment(((ExperimentWrapper) alt.getExperiment()).getExperiment(records));
                    }
                }

                // CHECK NUMERIC TRANSFORMER THRESHOLDS
                for (Leaf l : plan.getTree().getRoot().getAllLeaves()) {
                    eu.scape_project.planning.model.transform.Transformer t = l.getTransformer();
                    if (t != null && t instanceof NumericTransformer) {
                        NumericTransformer nt = (NumericTransformer) t;
                        if (!nt.checkOrder()) {
                            StringBuffer sb = new StringBuffer("NUMERICTRANSFORMER THRESHOLD ERROR ");
                            sb.append(l.getName()).append("::NUMERICTRANSFORMER:: ");
                            sb.append(nt.getThreshold1()).append(" ").append(nt.getThreshold2()).append(" ")
                                    .append(nt.getThreshold3()).append(" ").append(nt.getThreshold4())
                                    .append(" ").append(nt.getThreshold5());
                            log.error(sb.toString());
                        }
                    }
                }

                /*
                 * establish references to selected alternative
                 */
                HashMap<String, Alternative> alternatives = new HashMap<String, Alternative>();
                for (Alternative alt : plan.getAlternativesDefinition().getAlternatives()) {
                    alternatives.put(alt.getName(), alt);
                }
                if ((plan.getRecommendation() != null)
                        && (plan.getRecommendation() instanceof RecommendationWrapper)) {
                    plan.setRecommendation(
                            ((RecommendationWrapper) plan.getRecommendation()).getRecommendation(alternatives));
                }
                if ((plan.getPlanProperties().getState() == PlanState.ANALYSED)
                        && ((plan.getRecommendation() == null)
                                || (plan.getRecommendation().getAlternative() == null))) {
                    /*
                     * This project is NOT completely analysed
                     */
                    plan.getPlanProperties().setState(PlanState.valueOf(PlanState.ANALYSED.getValue() - 1));
                }

            } else {
                throw new PlatoException("Could not find any project data.");
            }
        }
    } catch (Exception e) {
        throw new PlatoException("Failed to import plans.", e);
    }

    return plans;
}

From source file:org.apache.commons.digester3.examples.api.addressbook.Main.java

/**
 * Main method : entry point for running this example program.
 * <p>//from w ww  .  j  ava  2 s  .  com
 * Usage: java Example example.xml
 */
public static void main(String[] args) {
    if (args.length != 1) {
        usage();
        System.exit(-1);
    }

    String filename = args[0];

    // Create a Digester instance
    Digester d = new Digester();

    // Prime the digester stack with an object for rules to
    // operate on. Note that it is quite common for "this"
    // to be the object pushed.
    AddressBook book = new AddressBook();
    d.push(book);

    // Add rules to the digester that will be triggered while
    // parsing occurs.
    addRules(d);

    // Process the input file.
    try {
        java.io.File srcfile = new java.io.File(filename);
        d.parse(srcfile);
    } catch (java.io.IOException ioe) {
        System.out.println("Error reading input file:" + ioe.getMessage());
        System.exit(-1);
    } catch (org.xml.sax.SAXException se) {
        System.out.println("Error parsing input file:" + se.getMessage());
        System.exit(-1);
    }

    // Print out all the contents of the address book, as loaded from
    // the input file.
    book.print();
}