Merge remote-tracking branch 'origin' into develop

This commit is contained in:
Brian Caruso 2013-03-05 17:15:58 -05:00
commit 08f583e280
110 changed files with 5057 additions and 1583 deletions

10
.gitignore vendored Normal file
View file

@ -0,0 +1,10 @@
/webapp/.build/
/.classpath
/.project
/.settings
/bin/
/webapp/config/deploy.properties
/webapp/config/build.properties
/webapp/config/runtime.properties
/webapp/config/debug.log4j.properties
.build

View file

@ -3,7 +3,7 @@
<head> <head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"> <meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="utf-8"> <meta charset="utf-8">
<title>Vitro Version 1.4 Installation Guide</title> <title>Vitro Version 1.5.1 Installation Guide</title>
<link rel="stylesheet" href="./css/doc.css" media="screen"> <link rel="stylesheet" href="./css/doc.css" media="screen">
</head> </head>
<body> <body>
@ -12,9 +12,9 @@
</div> </div>
<!-- Start of content --> <!-- Start of content -->
<div id="wrapper-content" role="main"> <div id="wrapper-content" role="main">
<h1>Vitro Version 1.4 Installation Guide</h1> <h1>Vitro Version 1.5. Installation Guide</h1>
<small> <small>
November 15, 2011 January 6, 2013
</small> </small>
<toc> <toc>
<ul> <ul>
@ -22,7 +22,7 @@
<a href="#introduction">Introduction to the Vitro installation</a> <a href="#introduction">Introduction to the Vitro installation</a>
</li> </li>
<li> <li>
<a href="#installation">Installation process for Version 1.4</a> <a href="#installation">Installation process for Version 1.5.1</a>
</li> </li>
</ul> </ul>
</toc> </toc>
@ -38,8 +38,13 @@
If you are upgrading a previous installation of Vitro, If you are upgrading a previous installation of Vitro,
you may need to adjust your procedure accordingly. you may need to adjust your procedure accordingly.
</p> </p>
<br> <p>
<hr><!-- Page break --><!-- Introduction to the Vitro installation --><h2 id="introduction">Introduction to the Vitro installation</h2> Other servlet containers: If you want to use a servlet container
other than Tomcat, please consult <a href="other_servlet_containers.html">
instructions for other servlet containers</a> in this directory.
</p>
<hr><h2 id="introduction">Introduction to the Vitro installation</h2>
<p> <p>
Before beginning the installation, Before beginning the installation,
@ -54,8 +59,8 @@
<p> <p>
This is created when you checkout the Vitro source code This is created when you checkout the Vitro source code
(see <a href="#checkout_code">installation step III</a>, below). (see <a href="#checkout_code">installation step III</a>, below).
This is where you will create your deploy.properties file This is where you will create your build.properties file
(see <a href="#deploy_properties">installation step V</a>, below), (see <a href="#build_properties">installation step IV</a>, below),
and where you will make any modifications to the Vitro and where you will make any modifications to the Vitro
theme or code. You can create this wherever you choose. theme or code. You can create this wherever you choose.
</p> </p>
@ -68,18 +73,20 @@
but you wont need to look at it or change it. If you need to change but you wont need to look at it or change it. If you need to change
Vitro, make the changes in the distribution directory, and run the build Vitro, make the changes in the distribution directory, and run the build
script again. Tell the build script where to find Tomcat by setting <code>tomcat.home</code> script again. Tell the build script where to find Tomcat by setting <code>tomcat.home</code>
in the deploy.properties file (see <a href="#deploy_properties">installation step V</a>, in the build.properties file (see <a href="#build_properties">installation step IV</a>,
below). below).
</p> </p>
<h4>The Vitro home directory</h4> <h4>The Vitro home directory</h4>
<p> <p>
Vitro will use this area to store some of the data it uses. Uploaded This directory contains the runtime configuration properties for Vitro.
image files are stored here, and the search index is stored here also. Vitro will also use this area to store some of the data it uses. Uploaded
image files are stored here, and the Solr home directory is stored here also.
You can create this wherever you choose. Tell Vitro where to find the You can create this wherever you choose. Tell Vitro where to find the
home directory by setting <code>vitro.home.directory</code> home directory by setting <code>vitro.home</code> in the
in the build.properties file (see <a href="#build_properties">installation step IV</a>,
deploy.properties file (see <a href="#deploy_properties">installation step V</a>, below). You must create this directory before starting Vitro,
below). You must create this directory before starting Vitro, and you you must create the <code>runtime.properties</code> file in this directory
(see <a href="#runtime_properties">Step V</a>, below), and you
must ensure that Tomcat has permission to read and write to this must ensure that Tomcat has permission to read and write to this
directory when it runs. directory when it runs.
</p> </p>
@ -176,7 +183,10 @@
<a href="#checkout_code">Check out the Vitro Source Code</a> <a href="#checkout_code">Check out the Vitro Source Code</a>
</li> </li>
<li> <li>
<a href="#deploy_properties">Specify deployment properties</a> <a href="#build_properties">Specify build properties</a>
</li>
<li>
<a href="#runtime_properties">Specify runtime properties</a>
</li> </li>
<li> <li>
<a href="#deploy">Compile and deploy</a> <a href="#deploy">Compile and deploy</a>
@ -275,12 +285,91 @@
If you want the very latest Vitro source, you can use subversion to check it out from SourceForge: If you want the very latest Vitro source, you can use subversion to check it out from SourceForge:
<pre> svn checkout svn://svn.code.sf.net/p/vivo/vitro/code/trunk</code> <em>[Vitro_distribution_dir]</em></pre> <pre> svn checkout svn://svn.code.sf.net/p/vivo/vitro/code/trunk</code> <em>[Vitro_distribution_dir]</em></pre>
</p> </p>
<h3 id="deploy_properties">IV. Specify deployment properties </h3>
<h3 id="build_properties">IV. Specify build properties </h3>
<p> <p>
In the <code>webapp/config</code> directory of the Vitro distribution, In the <code>webapp/config</code> directory of the Vitro distribution,
copy the file <code>example.deploy.properties</code> copy the file <code>example.build.properties</code>
to a file named simply <code>deploy.properties</code>. This file sets to a file named simply <code>build.properties</code>.
several properties used in compilation and deployment. Edit the file to suit your installation, as described in the following table.
</p>
<p>
These properties are used in compilation and deployment.
They will be incorporated into Vitro when it is compiled in
<a href="#deploy">Step VI</a>. If you want to change these properties at
a later date, you will need to stop Tomcat, repeat <a href="#deploy">Step VI</a>,
and restart Tomcat.
</p>
<p>
<em>Windows:</em>
For those installing on Windows operating
system, include the windows drive and use the forward slash "/" and not
the back slash "\" in the directory locations, e.g. <code>c:/tomcat</code>.
</p>
<table border='1' bordercolor="#CCCCCC" cellspacing="5">
<tbody>
<tr>
<td colspan="2">
Directory where tomcat is installed.
</td>
</tr>
<tr class="odd_row">
<td>
tomcat.home
</td>
<td>
/usr/local/tomcat
</td>
</tr>
<tr>
<td colspan="2">
Name of your Vitro application.
</td>
</tr>
<tr class="odd_row">
<td>
webapp.name
</td>
<td>
vitro
</td>
</tr>
<tr>
<td colspan="2">
Directory where the Vitro application will store
the data that it creates. This includes uploaded files (usually images)
and the Solr search index. Be sure this directory exists and is
writable by the user who the Tomcat service is running as.
</td>
</tr>
<tr class="odd_row">
<td>
vitro.home
</td>
<td>
/usr/local/vitro/home
</td>
</tr>
</tr>
</tbody>
</table>
<h3 id="runtime_properties">V. Specify runtime properties </h3>
<p>
In <a href="#build_properties">Step IV</a>, you defined the location of the Vitro home directory,
by specifying <code>vitro.home</code> in the <code>build.properties</code> file.
Create that directory now.
</p>
<p>
In the <code>webapp/config</code> subdirectory of the Vitro distribution, you will find a file called
<code>example.runtime.properties</code>. Copy this to the Vitro home directory you have created,
renaming the copy to <code>runtime.properties</code>.
Edit the file to suit your installation, as described in the following table.
</p>
<p>
These properties are loaded when Vitro starts up. If you want to change these
properties at a later date, you will need to restart Tomcat for them to take
effect. You will not need to repeat <a href="#deploy">Step VI</a>.
</p> </p>
<p> <p>
<em>Windows:</em> <em>Windows:</em>
@ -329,32 +418,6 @@
http://vitro.mydomain.edu/individual/ http://vitro.mydomain.edu/individual/
</td> </td>
</tr> </tr>
<tr>
<td colspan="2">
Directory where tomcat is installed.
</td>
</tr>
<tr class="odd_row">
<td>
tomcat.home
</td>
<td>
/usr/local/tomcat
</td>
</tr>
<tr>
<td colspan="2">
Name of your Vitro application.
</td>
</tr>
<tr class="odd_row">
<td>
webapp.name
</td>
<td>
vitro
</td>
</tr>
<tr> <tr>
<td colspan="2"> <td colspan="2">
URL of Solr context used in local Vitro search. URL of Solr context used in local Vitro search.
@ -372,53 +435,6 @@
http://localhost:8080/vitrosolr http://localhost:8080/vitrosolr
</td> </td>
</tr> </tr>
<tr>
<td colspan="2">
Restricts access to the Solr search platform.
The value is a regular expression. When a request is
made to Solr, the IP address of the requestor must the expression,
or the request will be rejected.
<br>
Examples:<code>
<ul>
<li>
vitro.local.solr.ipaddress.mask = 127\.0\.0\.1
</li>
<li>
vitro.local.solr.ipaddress.mask =
127\.0\.0\.1|0:0:0:0:0:0:0:1
</li>
<li>
vitro.local.solr.ipaddress.mask = 169.254.*
</li>
</ul>
</code>
</td>
</tr>
<tr class="odd_row">
<td>
vitro.local.solr.ipaddress.mask
</td>
<td>
127\.0\.0\.1|[0:]+:1
</td>
</tr>
<tr>
<td colspan="2">
Directory where the Vitro application will store
the data that it creates. This includes uploaded files (usually images)
and the Solr search index. Be sure this directory exists and is
writable by the user who the Tomcat service is running as.
</td>
</tr>
<tr class="odd_row">
<td>
vitro.home.directory
</td>
<td>
/usr/local/vitro/data
</td>
</tr>
<tr> <tr>
<td colspan="2"> <td colspan="2">
Specify an SMTP host that the application will Specify an SMTP host that the application will
@ -635,13 +651,101 @@
</tr> </tr>
<tr> <tr>
<td colspan="2"> <td colspan="2">
An absolute file path, pointing to the root directory of the Harvester utility. Force VIVO to use a specific language or Locale instead of those
You must include the final slash. specified by the browser.
This affects RDF data retrieved from the model, if RDFService.languageFilter is true.
This also affects the text of pages that have been modified to support multiple languages.
</td> </td>
</tr> </tr>
<tr class="odd_row">
<td>
languages.forceLocale
</td>
<td>
en_US
</td>
</tr>
<tr>
<td colspan="2">
A list of supported languages or Locales that the user may choose to
use instead of the one specified by the browser. Selection images must
be available in the i18n/images directory of the theme.
This affects RDF data retrieved from the model, if RDFService.languageFilter is true.
This also affects the text of pages that have been modified to support multiple languages.
</td>
</tr>
<tr class="odd_row">
<td>
languages.selectableLocales
</td>
<td>
en, es, fr_FR
</td>
</tr>
<tr>
<td colspan="2">
<b>For developers only.</b>
Defeat the Freemarker template cache, so each template
is read from disk on each request. This permits developers to immediately
see the effect of changes to the template. The default is <code>false</code>, which
means that a cached copy of each template will be used for 60 seconds
before the disk is checked for a new version.
<br/><b>Setting this option to "true" slows down Vitro performance.</b>
</td>
</tr>
<tr class="odd_row">
<td>
developer.defeatFreemarkerCache
</td>
<td>
false
</td>
</tr>
<tr>
<td colspan="2">
<b>For developers only.</b>
Defeat the cache of language-specific text strings,
so the language file is read from disk on each request.
This permits developers to immediately
see the effect of changes to the text strings.
The default is <code>false</code>, which means that the language file is
read when VIVO starts up, or when a new theme is selected.
<br/><b>Setting this option to "true" slows down Vitro performance.</b>
</td>
</tr>
<tr class="odd_row">
<td>
developer.defeatI18nCache = true
</td>
<td>
false
</td>
</tr>
<tr>
<td colspan="2">
<b>For developers only.</b>
Add starting and ending delimiters to each Freemarker template, so you can see
which template were invoked by viewing the generated HTML.
The default is <code>false</code>.
<br/><b>Setting this option to "true" slows down Vitro performance.</b>
</td>
</tr>
<tr class="odd_row blue">
<td>
developer.insertFreemarkerDelimiters = true
</td>
<td>
false
</td>
</tr>
</tbody> </tbody>
</table> </table>
<h3 id="deploy">V. Compile and deploy</h3> <h3 id="deploy">VI. Compile and deploy</h3>
<p> <p>
At the command line, change to the <code>webapp</code> directory inside the Vitro distribution At the command line, change to the <code>webapp</code> directory inside the Vitro distribution
directory. Then type: directory. Then type:
@ -650,7 +754,7 @@
<p> <p>
to build Vitro and deploy to Tomcat's webapps directory. to build Vitro and deploy to Tomcat's webapps directory.
</p> </p>
<h3 id="tomcat_settings">VI. Configure Tomcat</h3> <h3 id="tomcat_settings">VII. Configure Tomcat</h3>
<h4>Set JVM parameters</h4> <h4>Set JVM parameters</h4>
<p> <p>
Vitro may require more memory than that allocated to Tomcat by Vitro may require more memory than that allocated to Tomcat by
@ -686,7 +790,7 @@
accepting percent-encoded UTF-8. accepting percent-encoded UTF-8.
</p> </p>
<p> <p>
Edit Tomcat's conf/server.xml and add the following attribute to each of the Edit Tomcat's <code>conf/server.xml</code> and add the following attribute to each of the
Connector elements: URIEncoding="UTF-8". Connector elements: URIEncoding="UTF-8".
</p> </p>
<pre> <pre>
@ -699,6 +803,9 @@
&lt;/Server&gt; &lt;/Server&gt;
</pre> </pre>
<p> <p>
Note: some versions of Tomcat already include this attribute as the default.
</p>
<h4>Take care when creating Context elements</h4> <h4>Take care when creating Context elements</h4>
<p> <p>
Each of the webapps in the Vitro distribution (Vitro and Solr) includes a "context fragment" file, Each of the webapps in the Vitro distribution (Vitro and Solr) includes a "context fragment" file,
@ -710,22 +817,35 @@
deployment parameters from the overridden context fragment. deployment parameters from the overridden context fragment.
</p> </p>
<p> <p>
See <a href="#tomcat_connector">Section X</a> below, See <a href="#tomcat_connector">Section XI</a> below,
for an example of overriding the Vitro context fragment. for an example of overriding the Vitro context fragment.
</p> </p>
<h3 id="start_tomcat">VII. Start Tomcat </h3> <h3 id="start_tomcat">VIII. Start Tomcat </h3>
<p> <p>
Most Tomcat installations can be started by running <code>startup.sh</code> Most Tomcat installations can be started by running <code>startup.sh</code>
or <code>startup.bat</code> or <code>startup.bat</code>
in Tomcat's bin directory. Point your in Tomcat's bin directory. Point your
browser to "http://localhost:8080/vitro/" to test the application. If browser to "http://localhost:8080/vitro/" to test the application.
Tomcat does not start up, or the Vitro application is not visible, check </p>
the files in Tomcat's logs directory. Error messages are commonly found <p>
On start up Vitro will run some diagnostic tests. If a
problem is detected, the normal Vitro pages will redirect
to a startup status page describing the problem. You
can stop tomcat, attempt to fix the problem and
proceeded from <a href="#deploy">Step VI</a>. The
startup status page may offer a continue link which
will allow you to use VIVO in spite of the problems.
</p>
<p>
If Tomcat does not start up, or the Vitro application is not visible, check
the files in Tomcat's <code>logs</code> directory. Error messages are commonly found
in <code>catalina.out</code> in <code>catalina.out</code>
or <code>localhost.log</code> or <code>localhost.log</code>
</p> </p>
<h3 id="add_rdf">VIII. Log in and add RDF data </h3>
</p>
<h3 id="add_rdf">IX. Log in and add RDF data </h3>
<p> <p>
If the startup was successful, you will see a welcome message If the startup was successful, you will see a welcome message
informing you that you have successfully installed Vitro. Click the "Log informing you that you have successfully installed Vitro. Click the "Log
@ -759,7 +879,7 @@
the page will show a simple index of the knowledge base. the page will show a simple index of the knowledge base.
</p> </p>
<h3 id="contact_email">IX. Set the Contact Email Address (if using <h3 id="contact_email">X. Set the Contact Email Address (if using
"Contact Us" form)</h3> "Contact Us" form)</h3>
<p> <p>
If you have configured your application to use the "Contact Us" If you have configured your application to use the "Contact Us"
@ -781,7 +901,7 @@
provide an email address in this step, your users will receive a java provide an email address in this step, your users will receive a java
error in the interface. error in the interface.
</p> </p>
<h3 id="tomcat_connector">X. Set up Apache Tomcat Connector </h3> <h3 id="tomcat_connector">XI. Set up Apache Tomcat Connector </h3>
<p> <p>
It is recommended that a Tomcat Connector such as mod_jk be used to It is recommended that a Tomcat Connector such as mod_jk be used to
ensure that the site address does not include the port number (e.g. ensure that the site address does not include the port number (e.g.
@ -832,16 +952,11 @@
cookies="true" &gt; cookies="true" &gt;
&lt;Manager pathname="" /&gt; &lt;Manager pathname="" /&gt;
&lt;Environment type="java.lang.String" override="false"
name="path.configuration"
value="deploy.properties"
/&gt;
&lt;/Context&gt; &lt;/Context&gt;
... ...
</pre> </pre>
<h3 id="external_auth">XI. Using an External Authentication System <h3 id="external_auth">XII. Using an External Authentication System
with Vitro </h3> with Vitro </h3>
<p> <p>
</p> </p>
@ -878,7 +993,7 @@
<h4>Configuring Vitro</h4> <h4>Configuring Vitro</h4>
<p> <p>
To enable external authentication, Vitro requires three values in To enable external authentication, Vitro requires three values in
the <code>deploy.properties</code> the <code>runtime.properties</code>
file. file.
</p> </p>
<ul> <ul>
@ -893,7 +1008,7 @@
</p> </p>
<p> <p>
You need to tell Vitro the name of that HTTP header. Insert a You need to tell Vitro the name of that HTTP header. Insert a
line like this in the deploy.properties file: line like this in the runtime.properties file:
</p> </p>
<pre>externalAuth.netIdHeaderName = [the header name]</pre> <pre>externalAuth.netIdHeaderName = [the header name]</pre>
<p> <p>
@ -907,7 +1022,7 @@
the Vitro login form. You need to tell Vitro what text should appear in the Vitro login form. You need to tell Vitro what text should appear in
that button. that button.
<p> <p>
Put a line like this in the deploy.properties file: Put a line like this in the runtime.properties file:
externalAuth.buttonText = [the text for your login button] For example: externalAuth.buttonText = [the text for your login button] For example:
</p> </p>
<pre>externalAuth.buttonText = Log in using BearCat Shibboleth</pre> <pre>externalAuth.buttonText = Log in using BearCat Shibboleth</pre>
@ -924,7 +1039,7 @@
data model for a person with a property that matches the Users network data model for a person with a property that matches the Users network
ID (the value of the property must be either a String literal or an ID (the value of the property must be either a String literal or an
untyped literal). You need to tell Vitro what property should be used untyped literal). You need to tell Vitro what property should be used
for matching. Insert a line like this in the deploy.properties file: for matching. Insert a line like this in the runtime.properties file:
</p> </p>
<pre>selfEditing.idMatchingProperty = [the URI of the property]</pre> <pre>selfEditing.idMatchingProperty = [the URI of the property]</pre>
<p> <p>
@ -933,40 +1048,38 @@
<pre>selfEditing.idMatchingProperty = http://vitro.mydomain.edu/ns#networkId</pre> <pre>selfEditing.idMatchingProperty = http://vitro.mydomain.edu/ns#networkId</pre>
</li> </li>
</ul> </ul>
<h3 id="installation_check">XII. Was the installation successful? </h3> <h3 id="installation_check">XIII. Was the installation successful? </h3>
<p> <p>
If you have completed the previous steps, you have good indications If you have completed the previous steps, you have good indications
that the installation was successful. that the installation was successful.
</p> </p>
<ul> <ul>
<li> <li>
Step VII showed that Tomcat recognized the webapp, and that the Step VIII showed that Tomcat recognized the webapp, and that the
webapp was able to present the initial page. webapp was able to present the initial page.
</li> </li>
<li> <li>
Step VIII verified that you can log in to the administrator Step IX verified that you can log in to the administrator
account. account.
</li> </li>
</ul> </ul>
<p> <p>
Step VII also shows that the Vitro self-tests ran successfully. Step VIII also shows that the Vitro self-tests ran successfully.
When Tomcat starts the Vitro webapp, it runs several tests. When Tomcat starts the Vitro webapp, it runs several tests.
If any of these tests produce warnings or error message, If any of these tests produce warnings or error message,
you would see them instead of the Vitro home page. you would see them instead of the Vitro home page.
</p> </p>
<p> <p>
Among other things, the self-tests check Among other things, the self-tests check
</p> <ul>
<ul> <li>The Vitro home directory exists and Vitro can write to it.</li>
<li>The Vitro home directory exists and Vitro can write to it.</li> <li>Vitro can connect to the database.</li>
<li>Vitro can connect to the database.</li> <li>Vitro can connect to the Solr search application.</li>
<li>Vitro can connect to the Solr search application.</li> </ul>
</ul>
<p>
If you saw the Vitro home page in Step VII, you know that your installation passed all of these tests. If you saw the Vitro home page in Step VII, you know that your installation passed all of these tests.
</p> </p>
<h3 id="termsofuse">XIII. Review the Vitro Terms of Use</h3> <h3 id="termsofuse">XIV. Review the Vitro Terms of Use</h3>
<p> <p>
Vitro comes with a "Terms of Use" statement linked from the footer. Vitro comes with a "Terms of Use" statement linked from the footer.
The "Site Name" you assign in the "Site Information" form under the <strong>Site Admin</strong> The "Site Name" you assign in the "Site Information" form under the <strong>Site Admin</strong>
@ -992,7 +1105,7 @@
<div id="footer" role="contentinfo"> <div id="footer" role="contentinfo">
<p class="copyright"> <p class="copyright">
<small> <small>
©2011 All Rights Reserved ©2013 All Rights Reserved
</small> </small>
</p> </p>
</div> </div>

View file

@ -30,40 +30,53 @@ deploy - Configure the application and deploy directly into the Tomcat webapps
target: properties target: properties
- - - - - - - - - - - - - - - - - --> - - - - - - - - - - - - - - - - - -->
<target name="properties"> <target name="properties">
<property name="deploy.properties.file" location="../webapp/config/deploy.properties" /> <property name="build.properties.file" location="../webapp/config/build.properties" />
<fail message="You must create a &quot;${deploy.properties.file}&quot; file."> <fail message="You must create a &quot;${build.properties.file}&quot; file.">
<condition> <condition>
<not> <not>
<available file="${deploy.properties.file}" /> <available file="${build.properties.file}" />
</not> </not>
</condition> </condition>
</fail> </fail>
<property file="${deploy.properties.file}" /> <property file="${build.properties.file}" />
<fail unless="tomcat.home" message="${deploy.properties.file} must contain a value for tomcat.home" /> <fail unless="tomcat.home" message="${build.properties.file} must contain a value for tomcat.home" />
<fail unless="vitro.home.directory" message="${deploy.properties.file} must contain a value for vitro.home.directory" /> <fail unless="vitro.home" message="${build.properties.file} must contain a value for vitro.home" />
<fail unless="VitroConnection.DataSource.url" message="${deploy.properties.file} must contain a value for VitroConnection.DataSource.url" />
<fail unless="VitroConnection.DataSource.username" message="${deploy.properties.file} must contain a value for VitroConnection.DataSource.username" />
<fail unless="VitroConnection.DataSource.password" message="${deploy.properties.file} must contain a value for VitroConnection.DataSource.password" />
<fail unless="VitroConnection.DataSource.driver" message="${deploy.properties.file} must contain a value for VitroConnection.DataSource.driver" />
<fail unless="OpenSocial.shindigURL" message="${deploy.properties.file} must contain a value for OpenSocial.shindigURL" />
<fail unless="OpenSocial.tokenService" message="${deploy.properties.file} must contain a value for OpenSocial.tokenService" />
<fail unless="OpenSocial.tokenKeyFile" message="${deploy.properties.file} must contain a value for OpenSocial.tokenKeyFile" />
<fail message="The vitro.home.directory &quot;${vitro.home.directory}&quot; does not exist."> <property name="runtime.properties.file" location="${vitro.home}/runtime.properties" />
<fail message="The runtime properties file &quot;${runtime.properties.file}&quot; does not exist.">
<condition> <condition>
<not> <not>
<available file="${vitro.home.directory}" /> <available file="${runtime.properties.file}" />
</not> </not>
</condition> </condition>
</fail> </fail>
<fail message="The vitro.home.directory &quot;${vitro.home.directory}&quot; is not writable."> <property file="${runtime.properties.file}" />
<fail unless="VitroConnection.DataSource.url" message="${runtime.properties.file} must contain a value for VitroConnection.DataSource.url" />
<fail unless="VitroConnection.DataSource.username" message="${runtime.properties.file} must contain a value for VitroConnection.DataSource.username" />
<fail unless="VitroConnection.DataSource.password" message="${runtime.properties.file} must contain a value for VitroConnection.DataSource.password" />
<fail unless="VitroConnection.DataSource.driver" message="${runtime.properties.file} must contain a value for VitroConnection.DataSource.driver" />
<fail unless="OpenSocial.shindigURL" message="${runtime.properties.file} must contain a value for OpenSocial.shindigURL" />
<fail unless="OpenSocial.tokenService" message="${runtime.properties.file} must contain a value for OpenSocial.tokenService" />
<fail unless="OpenSocial.tokenKeyFile" message="${runtime.properties.file} must contain a value for OpenSocial.tokenKeyFile" />
<fail message="The Vitro home directory &quot;${vitro.home}&quot; does not exist.">
<condition> <condition>
<not> <not>
<isfileselected file="${vitro.home.directory}"> <available file="${vitro.home}" />
</not>
</condition>
</fail>
<fail message="The Vitro home directory &quot;${vitro.home}&quot; is not writable.">
<condition>
<not>
<isfileselected file="${vitro.home}">
<writable /> <writable />
</isfileselected> </isfileselected>
</not> </not>
@ -83,7 +96,7 @@ deploy - Configure the application and deploy directly into the Tomcat webapps
<property name="build.shindig.dir" location="${build.dir}/shindig" /> <property name="build.shindig.dir" location="${build.dir}/shindig" />
<!-- deploy directories --> <!-- deploy directories -->
<property name="shindig.home.dir" location="${vitro.home.directory}/shindig" /> <property name="shindig.home.dir" location="${vitro.home}/shindig" />
<property name="shindig.config.dir" location="${shindig.home.dir}/conf" /> <property name="shindig.config.dir" location="${shindig.home.dir}/conf" />
<property name="tomcat.webapps.dir" location="${tomcat.home}/webapps" /> <property name="tomcat.webapps.dir" location="${tomcat.home}/webapps" />
@ -145,5 +158,4 @@ deploy - Configure the application and deploy directly into the Tomcat webapps
<copy file="${shindig.war.original.file}" tofile="${shindig.war.deployed.file}" overwrite="true" /> <copy file="${shindig.war.original.file}" tofile="${shindig.war.deployed.file}" overwrite="true" />
</target> </target>
</project> </project>

Binary file not shown.

BIN
solr/apache-solr-3.6.2.war Normal file

Binary file not shown.

View file

@ -253,7 +253,7 @@
<!-- **************************** End Vitro Fields *************************** --> <!-- **************************** End Vitro Fields *************************** -->
<!-- **************************** Dynamic Fields *************************** --> <!-- **************************** Dynamic Fields *************************** -->
<dynamicField name="*_string" type="string" indexed="true" stored="true" /> <dynamicField name="*_string" type="string" indexed="true" stored="true" multiValued="true"/>
<!-- **************************** End Dynamic Fields *************************** --> <!-- **************************** End Dynamic Fields *************************** -->

View file

@ -1,11 +1,4 @@
<Context crossContext="true" override="true"> <Context crossContext="true" override="true">
<!-- For security, restrict access to clients on this machine
for IPv4 requests, localhost is 127.0.0.1
for IPv6 requests, localhost is 0:0:0:0:0:0:0:1 -->
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
allow="${vitro.local.solr.ipaddress.mask}"/>
<Environment <Environment
type="java.lang.String" type="java.lang.String"
name="solr/home" name="solr/home"

View file

@ -10,216 +10,226 @@
<project name="vitroCore" default="describe"> <project name="vitroCore" default="describe">
<!-- - - - - - - - - - - - - - - - - -
properties
- - - - - - - - - - - - - - - - -->
<dirname property="corebase.dir" file="${ant.file.vitroCore}" />
<!-- A product script will override appbase.dir, but not corebase.dir --> <!-- A product script will override appbase.dir, but not corebase.dir -->
<dirname property="corebase.dir" file="${ant.file.vitroCore}" />
<property name="appbase.dir" location="${corebase.dir}" /> <property name="appbase.dir" location="${corebase.dir}" />
<property name="build.properties.file" location="config/build.properties" />
<property name="build.dir" location=".build" /> <property name="build.dir" location=".build" />
<property name="deploy.properties.file" location="config/deploy.properties" />
<property name="utilities.base.dir" location="${corebase.dir}/../utilities/buildutils" /> <property name="buildtools.dir" location="${corebase.dir}/../utilities/buildutils" />
<property name="utilities.source.dir" location="${utilities.base.dir}/src" /> <property name="buildtools.source.dir" location="${buildtools.dir}/src" />
<property name="utilities.lib.dir" location="${utilities.base.dir}/lib" /> <property name="buildtools.lib.dir" location="${buildtools.dir}/lib" />
<property name="buildtools.compiled.dir" location="${build.dir}/buildTools" />
<property name="war.dir" location="${build.dir}/war" /> <property name="main.build.dir" location="${build.dir}/main"/>
<property name="war.webinf.dir" location="${war.dir}/WEB-INF" /> <property name="main.webapp.dir" location="${main.build.dir}/webapp" />
<property name="war.classes.dir" location="${war.webinf.dir}/classes" /> <property name="main.webinf.dir" location="${main.webapp.dir}/WEB-INF" />
<property name="war.resources.dir" location="${war.webinf.dir}/resources" /> <property name="main.compiled.dir" location="${main.webinf.dir}/classes" />
<property name="revisionInfo.build.file" location="${war.resources.dir}/revisionInfo.txt" /> <property name="main.resources.dir" location="${main.webinf.dir}/resources" />
<property name="main.revisioninfo.file" location="${main.resources.dir}/revisionInfo.txt" />
<property name="test.classes.dir" location="${build.dir}/testClasses" /> <property name="unittests.compiled.dir" location="${main.build.dir}/testClasses" />
<property name="utility.classes.dir" location="${build.dir}/utilityClasses" />
<property name="solr.template.dir" location="${corebase.dir}/../solr" />
<property name="solr.template.context.file" location="${solr.template.dir}/template.context.xml" />
<property name="solr.build.dir" location="${build.dir}/solr" /> <property name="solr.build.dir" location="${build.dir}/solr" />
<property name="solr.webapp.dir" location="${solr.build.dir}/webapp" />
<property name="solr.homeimage.dir" location="${solr.build.dir}/homeimage" />
<property name="javac.deprecation" value="true" /> <property name="distribution.dir" location="${build.dir}/distribution" />
<property name="distribution.tar.gz.file" location="${build.dir}/distribution.tar.gz" />
<property name="option.javac.deprecation" value="true" />
<!-- - - - - - - - - - - - - - - - - - <!-- - - - - - - - - - - - - - - - - -
paths: for compiling and running target: buildProperties
- - - - - - - - - - - - - - - - - --> - - - - - - - - - - - - - - - - - -->
<path id="compile.classpath"> <target name="buildProperties">
<fileset dir="${appbase.dir}/lib" includes="*.jar" /> <fail message="You must create a &quot;${build.properties.file}&quot; file.">
</path>
<path id="utility.compile.classpath">
<fileset dir="${utilities.lib.dir}" includes="*.jar" />
</path>
<path id="utility.run.classpath">
<pathelement location="${utility.classes.dir}" />
<path refid="utility.compile.classpath" />
</path>
<path id="test.compile.classpath">
<pathelement location="${war.classes.dir}" />
<path refid="compile.classpath" />
</path>
<path id="test.run.classpath">
<pathelement location="${appbase.dir}/test" />
<pathelement location="${test.classes.dir}" />
<path refid="test.compile.classpath" />
<path refid="utility.run.classpath" />
</path>
<!-- =================================
target: describe
================================= -->
<target name="describe" description="--> Describe the targets (this is the default).">
<echo>
all - Runs "clean", then "deploy".
clean - Delete all artifacts so the next build will be from scratch.
compile - Compile the Java source files.
orng - Configure and deploy the ORNG Shindig application.
test - Compile and run the JUnit tests.
war - Create a WAR file to be deployed in a servlet container.
deploy - Deploy the application directly into the Tomcat webapps directory.
</echo>
</target>
<!-- =================================
target: all
================================= -->
<target name="all" depends="clean, deploy" description="--> Run 'clean', then 'deploy'" />
<!-- - - - - - - - - - - - - - - - - -
target: properties
- - - - - - - - - - - - - - - - - -->
<target name="properties">
<fail message="You must create a &quot;${deploy.properties.file}&quot; file.">
<condition> <condition>
<not> <not>
<available file="${deploy.properties.file}" /> <available file="${build.properties.file}" />
</not> </not>
</condition> </condition>
</fail> </fail>
<property file="${deploy.properties.file}" /> <property file="${build.properties.file}" />
<fail unless="tomcat.home" message="${deploy.properties.file} must contain a value for tomcat.home" /> <fail unless="webapp.name" message="${build.properties.file} must contain a value for webapp.name" />
<fail unless="webapp.name" message="${deploy.properties.file} must contain a value for webapp.name" /> <property name="solr.app.name" value="${webapp.name}solr" />
<fail unless="vitro.home.directory" message="${deploy.properties.file} must contain a value for vitro.home.directory" />
<fail unless="Vitro.defaultNamespace" message="${deploy.properties.file} must contain a value for Vitro.defaultNamespace" />
<fail unless="VitroConnection.DataSource.url" message="${deploy.properties.file} must contain a value for VitroConnection.DataSource.url" />
<fail unless="VitroConnection.DataSource.username" message="${deploy.properties.file} must contain a value for VitroConnection.DataSource.username" />
<fail unless="VitroConnection.DataSource.password" message="${deploy.properties.file} must contain a value for VitroConnection.DataSource.password" />
<fail unless="rootUser.emailAddress" message="${deploy.properties.file} must contain a value for rootUser.emailAddress" />
<fail message="The vitro.home.directory &quot;${vitro.home.directory}&quot; does not exist.">
<condition>
<not>
<available file="${vitro.home.directory}" />
</not>
</condition>
</fail>
<fail message="The vitro.home.directory &quot;${vitro.home.directory}&quot; is not writable.">
<condition>
<not>
<isfileselected file="${vitro.home.directory}">
<writable />
</isfileselected>
</not>
</condition>
</fail>
<property name="solr.home.dir" location="${vitro.home.directory}/solr" />
</target>
<!-- =================================
target: clean
================================= -->
<target name="clean" depends="properties" description="--> Delete all artifacts.">
<delete dir="${build.dir}" />
<delete dir="${solr.home.dir}" excludes="data/**/*" includeemptydirs="true" />
</target> </target>
<!-- - - - - - - - - - - - - - - - - - <!-- - - - - - - - - - - - - - - - - -
target: compileUtilities target: deployProperties
- - - - - - - - - - - - - - - - - --> - - - - - - - - - - - - - - - - - -->
<target name="compileUtilities"> <target name="deployProperties" depends="buildProperties">
<mkdir dir="${utility.classes.dir}" /> <fail unless="vitro.home" message="${build.properties.file} must contain a value for vitro.home" />
<javac srcdir="${utilities.source.dir}" destdir="${utility.classes.dir}" debug="true" deprecation="${javac.deprecation}" encoding="UTF8" includeantruntime="false" optimize="false" source="1.6"> <fail unless="tomcat.home" message="${build.properties.file} must contain a value for tomcat.home" />
<property name="solr.home.dir" location="${vitro.home}/solr" />
<property name="tomcat.context.filename" value="META-INF/context.xml" />
<property name="main.tomcat.webapp.dir" value="${tomcat.home}/webapps/${webapp.name}" />
<property name="main.tomcat.context.file" value="${main.tomcat.webapp.dir}/${tomcat.context.filename}" />
<property name="solr.tomcat.webapp.dir" value="${tomcat.home}/webapps/${solr.app.name}" />
<property name="solr.tomcat.context.file" value="${solr.tomcat.webapp.dir}/${tomcat.context.filename}" />
</target>
<!-- - - - - - - - - - - - - - - - - -
target: compileBuildtools
- - - - - - - - - - - - - - - - - -->
<target name="compileBuildtools">
<path id="utility.compile.classpath">
<fileset dir="${buildtools.lib.dir}" includes="*.jar" />
</path>
<mkdir dir="${buildtools.compiled.dir}" />
<javac srcdir="${buildtools.source.dir}"
destdir="${buildtools.compiled.dir}"
debug="true"
deprecation="${option.javac.deprecation}"
encoding="UTF8"
includeantruntime="false"
optimize="false"
source="1.6">
<classpath refid="utility.compile.classpath" /> <classpath refid="utility.compile.classpath" />
</javac> </javac>
<path id="utility.run.classpath">
<pathelement location="${buildtools.compiled.dir}" />
<path refid="utility.compile.classpath" />
</path>
</target> </target>
<!-- - - - - - - - - - - - - - - - - - <!-- - - - - - - - - - - - - - - - - -
target: prepare target: prepare
- - - - - - - - - - - - - - - - - --> - - - - - - - - - - - - - - - - - -->
<target name="prepare" depends="properties, compileUtilities"> <target name="prepare">
<mkdir dir="${build.dir}" /> <mkdir dir="${build.dir}" />
<mkdir dir="${war.classes.dir}" /> </target>
<mkdir dir="${war.resources.dir}" />
<mkdir dir="${test.classes.dir}" />
<!-- copy all sorts of web stuff into the war directory. --> <!-- - - - - - - - - - - - - - - - - -
<copy todir="${war.dir}"> target: prepareWebappDir
- - - - - - - - - - - - - - - - - -->
<target name="prepareWebappDir" depends="prepare">
<!-- copy all sorts of web stuff into the webapp directory. -->
<copy todir="${main.webapp.dir}">
<fileset dir="${appbase.dir}/web" /> <fileset dir="${appbase.dir}/web" />
<fileset dir="${appbase.dir}" includes="themes/**/*" /> <fileset dir="${appbase.dir}" includes="themes/**/*" />
</copy> </copy>
<copy todir="${war.webinf.dir}"> <copy todir="${main.webinf.dir}">
<fileset dir="${appbase.dir}"> <fileset dir="${appbase.dir}">
<!-- copy the JARs into the war directory --> <!-- copy the JARs into the war directory -->
<include name="lib/*" /> <include name="lib/*" />
<!-- these are already in Tomcat: we mustn't conflict. --> <!-- these will be in the servlet container: we mustn't conflict. -->
<exclude name="lib/jsp-api.jar" /> <exclude name="lib/jsp-api.jar" />
<exclude name="lib/servlet-api.jar" /> <exclude name="lib/servlet-api.jar" />
</fileset> </fileset>
</copy> </copy>
<!-- use the production Log4J properties, unless a debug version exists. --> <!-- use the production Log4J properties, unless a debug version exists. -->
<available file="${appbase.dir}/config/debug.log4j.properties" property="debug.log4j.exists" /> <condition property="log4j.properties.file" value="debug.log4j.properties" else="default.log4j.properties">
<copy tofile="${war.classes.dir}/log4j.properties" filtering="true" overwrite="true"> <available file="${appbase.dir}/config/debug.log4j.properties" />
<fileset dir="${appbase.dir}/config"> </condition>
<include name="default.log4j.properties" unless="debug.log4j.exists" /> <copy file="${appbase.dir}/config/${log4j.properties.file}"
<include name="debug.log4j.properties" if="debug.log4j.exists" /> tofile="${main.build.dir}/log4j.properties"
</fileset> filtering="true"
overwrite="true">
<filterchain> <filterchain>
<expandproperties /> <expandproperties />
</filterchain> </filterchain>
</copy> </copy>
<copy todir="${main.compiled.dir}">
<copy todir="${war.classes.dir}"> <fileset dir="${main.build.dir}">
<!-- copy the deploy.properties into the war directory --> <filename name="log4j.properties"/>
<fileset file="${deploy.properties.file}" /> <different targetdir="${main.compiled.dir}" ignorefiletimes="true"/>
</fileset>
<!-- copy any xml files from source tree to the war directory -->
<fileset dir="${appbase.dir}/src" includes="**/*.xml" />
</copy> </copy>
<!-- copy the context file into the war directory --> <!-- Copy the build.properties file to the resources directory. -->
<copy file="${appbase.dir}/context.xml" tofile="${war.dir}/META-INF/context.xml" /> <copy todir="${main.resources.dir}" file="${build.properties.file}" />
<!-- If there is a runtime.properties file in the same directory as build.properties, copy that too. -->
<dirname file="${build.properties.file}" property="runtime.properties.dir"/>
<copy todir="${main.resources.dir}" >
<fileset dir="${runtime.properties.dir}" >
<filename name="runtime.properties" />
</fileset>
</copy>
<!-- copy any xml files from source tree to the war directory -->
<copy todir="${main.compiled.dir}">
<fileset dir="${appbase.dir}/src" includes="**/*.xml" />
</copy>
</target>
<!-- =================================
target: clean
================================= -->
<target name="clean" description="--> Delete all artifacts.">
<delete dir="${build.dir}" />
</target> </target>
<!-- ================================= <!-- =================================
target: compile target: compile
================================= --> ================================= -->
<target name="compile" depends="prepare" description="--> Compile Java sources"> <target name="compile" depends="prepareWebappDir" description="--> Compile Java sources">
<path id="main.compile.classpath">
<fileset dir="${appbase.dir}/lib" includes="*.jar" />
</path>
<!-- deletes all files that depend on changed .java files --> <!-- deletes all files that depend on changed .java files -->
<depend srcdir="${appbase.dir}/src" destdir="${war.classes.dir}" closure="false" cache="${build.dir}/.depcache"> <depend srcdir="${appbase.dir}/src"
<classpath refid="compile.classpath" /> destdir="${main.compiled.dir}"
closure="false"
cache="${main.build.dir}/compileDependencyCache">
<classpath refid="main.compile.classpath" />
</depend> </depend>
<javac srcdir="${appbase.dir}/src" destdir="${war.classes.dir}" debug="true" deprecation="${javac.deprecation}" encoding="UTF8" includeantruntime="false" optimize="true" source="1.6"> <javac srcdir="${appbase.dir}/src"
<classpath refid="compile.classpath" /> destdir="${main.compiled.dir}"
debug="true"
deprecation="${option.javac.deprecation}"
encoding="UTF8"
includeantruntime="false"
optimize="true"
source="1.6">
<classpath refid="main.compile.classpath" />
</javac> </javac>
</target> </target>
<!-- ================================= <!-- =================================
target: test target: test
================================= --> ================================= -->
<target name="test" depends="compile" unless="skiptests" description="--> Run JUnit tests"> <target name="test" depends="compile, compileBuildtools" unless="skiptests" description="--> Run JUnit tests">
<javac srcdir="${appbase.dir}/test" destdir="${test.classes.dir}" debug="true" deprecation="${javac.deprecation}" encoding="UTF8" includeantruntime="false" optimize="false" source="1.6"> <path id="test.compile.classpath">
<pathelement location="${main.compiled.dir}" />
<path refid="main.compile.classpath" />
</path>
<mkdir dir="${unittests.compiled.dir}" />
<javac srcdir="${appbase.dir}/test"
destdir="${unittests.compiled.dir}"
debug="true"
deprecation="${option.javac.deprecation}"
encoding="UTF8"
includeantruntime="false"
optimize="false"
source="1.6">
<classpath refid="test.compile.classpath" /> <classpath refid="test.compile.classpath" />
</javac> </javac>
<path id="test.run.classpath">
<pathelement location="${appbase.dir}/test" />
<pathelement location="${unittests.compiled.dir}" />
<path refid="test.compile.classpath" />
<path refid="utility.run.classpath" />
</path>
<java classname="edu.cornell.mannlib.vitro.utilities.testing.VitroTestRunner" fork="yes" failonerror="true"> <java classname="edu.cornell.mannlib.vitro.utilities.testing.VitroTestRunner" fork="yes" failonerror="true">
<classpath refid="test.run.classpath" /> <classpath refid="test.run.classpath" />
<arg file="${appbase.dir}/test" /> <arg file="${appbase.dir}/test" />
@ -227,113 +237,161 @@ deploy - Deploy the application directly into the Tomcat webapps directory.
</java> </java>
</target> </target>
<!-- =================================
target: jar
================================= -->
<target name="jar" depends="test" description="--> Compile the Java, and build a JAR file">
<jar basedir="${war.classes.dir}" destfile="${build.dir}/${ant.project.name}.jar" />
</target>
<!-- ================================= <!-- =================================
target: revisionInfo target: revisionInfo
================================= --> ================================= -->
<target name="revisionInfo" depends="test" unless="skipinfo" description="--> Store revision info in build"> <target name="revisionInfo" depends="test" unless="skipinfo" description="--> Store revision info in build">
<mkdir dir="${main.resources.dir}" />
<tstamp> <tstamp>
<format property="revisionInfo.timestamp" pattern="yyyy-MM-dd HH:mm:ss" /> <format property="revisionInfo.timestamp" pattern="yyyy-MM-dd HH:mm:ss" />
</tstamp> </tstamp>
<echo file="${revisionInfo.build.file}">${revisionInfo.timestamp} <echo file="${main.revisioninfo.file}">${revisionInfo.timestamp}
</echo> </echo>
<addRevisionInfoLine productName="vitroCore" productCheckoutDir="${corebase.dir}/.." /> <addRevisionInfoLine productName="vitroCore" productCheckoutDir="${corebase.dir}/.." />
</target> </target>
<!-- - - - - - - - - - - - - - - - - - <!-- - - - - - - - - - - - - - - - - -
target: prepareSolr target: deployWebapp
- - - - - - - - - - - - - - - - - --> - - - - - - - - - - - - - - - - - -->
<target name="prepareSolr" depends="properties" unless="skipsolr"> <target name="deployWebapp" depends="deployProperties, revisionInfo">
<mkdir dir="${solr.home.dir}" /> <mkdir dir="${main.tomcat.webapp.dir}" />
<mkdir dir="${solr.build.dir}" />
<property name="solr.distrib.dir" location="${corebase.dir}/../solr" /> <sync todir="${main.tomcat.webapp.dir}" includeemptydirs="true">
<property name="solr.home.template.dir" location="${solr.distrib.dir}/homeDirectoryTemplate" /> <fileset dir="${main.webapp.dir}" />
<property name="solr.context.template.file" location="${solr.distrib.dir}/template.context.xml" /> <preserveintarget>
<property name="solr.distrib.war" location="${solr.distrib.dir}/apache-solr-3.1.0.war" /> <include name="${tomcat.context.filename}"/>
</preserveintarget>
</sync>
<property name="solr.context.file" location="${solr.build.dir}/context.xml" /> <!-- Create the context XML with expanded properties. Store it in a temp file for now. -->
<property name="solr.context.temp.file" location="${solr.build.dir}/context.temp.xml" /> <copy tofile="${main.build.dir}/context.xml" filtering="true" overwrite="true">
<property name="solr.build.war" location="${solr.build.dir}/solr.war" /> <fileset file="${appbase.dir}/context.xml" />
<property name="solr.context.name" value="${webapp.name}solr" />
<property name="solr.deployed.war" value="${tomcat.home}/webapps/${solr.context.name}.war" />
<!-- if no mask is defined, leave Solr unsecured. -->
<property name="vitro.local.solr.ipaddress.mask" value=".*" />
<!-- Create and copy the example directory to the solr.home.dir directory. -->
<copy todir="${solr.home.dir}">
<fileset dir="${solr.home.template.dir}" includes="**/*" />
</copy>
<!-- Create the context configuration XML with expanded properties. Store it in a temp file for now. -->
<copy tofile="${solr.context.temp.file}" filtering="true" overwrite="true">
<fileset file="${solr.context.template.file}" />
<filterchain> <filterchain>
<expandproperties /> <expandproperties />
</filterchain> </filterchain>
</copy> </copy>
<!-- If the WAR is up to date and the context file hasn't changed, we can skip the deploy. --> <!-- Copy the new context XML only if it differs from the existing one. -->
<condition property="skipsolr"> <copy todir="${main.tomcat.webapp.dir}/META-INF">
<and> <fileset dir="${main.build.dir}">
<uptodate targetfile="${solr.build.war}"> <filename name="context.xml"/>
<srcfiles file="${solr.distrib.war}" /> <different targetdir="${main.tomcat.webapp.dir}/META-INF" ignorefiletimes="true"/>
<srcfiles dir="${appbase.dir}/config/solr/" /> </fileset>
</uptodate> </copy>
<filesmatch file1="${solr.context.temp.file}" file2="${solr.context.file}" /> </target>
<filesmatch file1="${solr.context.temp.file}" file2="${tomcat.home}/webapps/${solr.context.name}/META-INF/context.xml" />
</and> <!-- - - - - - - - - - - - - - - - - -
</condition> target: prepareSolr
- - - - - - - - - - - - - - - - - -->
<target name="prepareSolr" depends="prepare, buildProperties">
<!-- create an image of the Solr home directory -->
<copy todir="${solr.homeimage.dir}">
<fileset dir="${solr.template.dir}/homeDirectoryTemplate" />
</copy>
<!-- create an unpacked image of the Solr WAR, with our config options -->
<unwar src="${solr.template.dir}/apache-solr-3.6.2.war" dest="${solr.webapp.dir}" />
<copy todir="${solr.webapp.dir}/WEB-INF/classes">
<fileset dir="${appbase.dir}/config/solr/" />
</copy>
</target> </target>
<!-- - - - - - - - - - - - - - - - - - <!-- - - - - - - - - - - - - - - - - -
target: deploySolr target: deploySolr
- - - - - - - - - - - - - - - - - --> - - - - - - - - - - - - - - - - - -->
<target name="deploySolr" depends="prepareSolr" unless="skipsolr"> <target name="deploySolr" depends="deployProperties, prepareSolr">
<!-- save the new context file, so we can compare against it next time. --> <!-- Deploy to the Solr home directory. -->
<copy file="${solr.context.temp.file}" tofile="${solr.context.file}" /> <mkdir dir="${solr.home.dir}" />
<sync todir="${solr.home.dir}" includeemptydirs="true">
<war destfile="${solr.build.war}" needxmlfile="false"> <fileset dir="${solr.homeimage.dir}" />
<zipfileset src="${solr.distrib.war}" /> <preserveintarget>
<classes dir="${appbase.dir}/config/solr" /> <include name="data/**/*"/>
<metainf file="${solr.context.file}" /> </preserveintarget>
</war>
<!-- deploy the new WAR -->
<unwar src="${solr.build.war}" dest="${tomcat.home}/webapps/${solr.context.name}" />
</target>
<!-- =================================
target: deploy
================================= -->
<target name="deploy" depends="revisionInfo, deploySolr" description="--> Build the app and install in Tomcat">
<property name="webapp.deploy.home" value="${tomcat.home}/webapps/${webapp.name}" />
<mkdir dir="${webapp.deploy.home}" />
<sync todir="${webapp.deploy.home}" includeemptydirs="true">
<fileset dir="${build.dir}/war" />
</sync> </sync>
<!-- Deploy to Tomcat. -->
<mkdir dir="${solr.tomcat.webapp.dir}" />
<sync todir="${solr.tomcat.webapp.dir}" includeemptydirs="true">
<fileset dir="${solr.webapp.dir}" />
<preserveintarget>
<include name="${tomcat.context.filename}"/>
</preserveintarget>
</sync>
<!-- Create the context XML with expanded properties. Store it in a temp file for now. -->
<copy tofile="${solr.build.dir}/context.xml" filtering="true" overwrite="true">
<fileset file="${solr.template.context.file}" />
<filterchain>
<expandproperties />
</filterchain>
</copy>
<!-- Copy the new context XML only if it differs from the existing one. -->
<copy todir="${solr.tomcat.webapp.dir}/META-INF">
<fileset dir="${solr.build.dir}">
<filename name="context.xml"/>
<different targetdir="${solr.tomcat.webapp.dir}/META-INF" ignorefiletimes="true"/>
</fileset>
</copy>
</target> </target>
<!-- ================================= <!-- =================================
target: war target: deploy
================================= --> ================================= -->
<target name="war" depends="revisionInfo" description="--> Build the app and create a WAR file"> <target name="deploy"
<jar basedir="${build.dir}/war" destfile="${build.dir}/${webapp.name}.war" /> depends="deployWebapp, deploySolr"
description="--> Build the app and install in Tomcat">
</target> </target>
<!-- =================================
target: all
================================= -->
<target name="all" depends="clean, deploy" description="--> Run 'clean', then 'deploy'" />
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
OUTSIDE THE MAIN BUILD SEQUENCE
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<!-- =================================
target: distribute
================================= -->
<target name="distribute"
depends="revisionInfo, prepareSolr"
description="--> Build the app and create a distribution bundle">
<mkdir dir="${distribution.dir}" />
<jar basedir="${main.webapp.dir}" destfile="${distribution.dir}/${webapp.name}.war" />
<jar basedir="${solr.webapp.dir}" destfile="${distribution.dir}/${solr.app.name}.war" />
<tar basedir="${solr.homeimage.dir}" destfile="${distribution.dir}/solrhome.tar" />
<tar basedir="${distribution.dir}" destfile="${distribution.tar.gz.file}" compression="gzip" />
</target>
<!-- =================================
target: describe
================================= -->
<target name="describe"
description="--> Describe the targets (this is the default).">
<echo>
all - Runs "clean", then "deploy".
clean - Delete all artifacts so the next build will be from scratch.
compile - Compile the Java source files.
orng - Configure and deploy the ORNG Shindig application.
test - Compile and run the JUnit tests.
distribute - Create WAR files to be deployed in a servlet container.
deploy - Deploy the application directly into the Tomcat webapps directory.
</echo>
</target>
<!-- =================================
target: jar
================================= -->
<target name="jar" depends="test" description="--> Compile the Java, and build a JAR file">
<jar basedir="${main.compiled.dir}" destfile="${build.dir}/${ant.project.name}.jar" />
</target>
<!-- ================================= <!-- =================================
target: licenser target: licenser
@ -348,7 +406,7 @@ deploy - Deploy the application directly into the Tomcat webapps directory.
<!-- ================================= <!-- =================================
target: jarlist target: jarlist
================================= --> ================================= -->
<target name="jarlist" depends="jar" description="Figure out what JARs are not needed"> <target name="jarlist" depends="compileBuildtools, jar" description="Figure out what JARs are not needed">
<java classname="edu.cornell.mannlib.vitro.utilities.jarlist.JarLister" fork="no" failonerror="true"> <java classname="edu.cornell.mannlib.vitro.utilities.jarlist.JarLister" fork="no" failonerror="true">
<classpath refid="utility.run.classpath" /> <classpath refid="utility.run.classpath" />
<arg value="${build.dir}/${ant.project.name}.jar" /> <arg value="${build.dir}/${ant.project.name}.jar" />
@ -393,13 +451,16 @@ deploy - Deploy the application directly into the Tomcat webapps directory.
<attribute name="productName" /> <attribute name="productName" />
<attribute name="productCheckoutDir" /> <attribute name="productCheckoutDir" />
<sequential> <sequential>
<java classname="edu.cornell.mannlib.vitro.utilities.revisioninfo.RevisionInfoBuilder" fork="no" failonerror="true"> <java classname="edu.cornell.mannlib.vitro.utilities.revisioninfo.RevisionInfoBuilder"
fork="no"
failonerror="true">
<classpath refid="utility.run.classpath" /> <classpath refid="utility.run.classpath" />
<arg value="@{productName}" /> <arg value="@{productName}" />
<arg file="@{productCheckoutDir}" /> <arg file="@{productCheckoutDir}" />
<arg file="${revisionInfo.build.file}" /> <arg file="${main.revisioninfo.file}" />
</java> </java>
</sequential> </sequential>
</macrodef> </macrodef>
</project> </project>

View file

@ -0,0 +1,29 @@
# -----------------------------------------------------------------------------
#
# Vitro build properties
#
# This file is provided as example.build.properties.
#
# Save a copy of this file as build.properties, and edit the properties as
# needed for your installation.
#
# -----------------------------------------------------------------------------
#
# The base install directory for your Tomcat server. The Vitro application
# will be deployed in the /webapps directory below this base.
#
tomcat.home = /usr/local/tomcat
#
# The name of the Vitro application. This will be used as the name of the
# subdirectory within your Tomcat server's /webapps directory. It also appears
# in the URL for the application. For example, http://my.vitro.server/vitro
#
webapp.name = vitro
#
# The location where the Vitro application will store the data that it creates.
# This includes uploaded files (usually images) and the search index.
#
vitro.home = /usr/local/vitro/home

View file

@ -1,11 +1,11 @@
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# #
# Vitro deployment properties # Vitro runtime properties
# #
# This file is provided as example.deploy.properties. # This file is provided as example.runtime.properties.
# #
# Save a copy of this file as deploy.properties, and edit the properties as # Save a copy of this file as runtime.properties in your Vitro home directory,
# needed for your deployment. # and edit the properties as needed for your installation.
# #
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@ -22,19 +22,6 @@
# #
Vitro.defaultNamespace = http://vivo.mydomain.edu/individual/ Vitro.defaultNamespace = http://vivo.mydomain.edu/individual/
#
# The base install directory for your Tomcat server. The Vitro application
# will be deployed in the /webapps directory below this base.
#
tomcat.home = /usr/local/tomcat
#
# The name of the Vitro application. This will be used as the name of the
# subdirectory within your Tomcat server's /webapps directory. It also appears
# in the URL for the application. For example, http://my.vitro.server/vitro
#
webapp.name = vitro
# #
# URL of Solr context used in local Vitro search. This will usually consist of: # URL of Solr context used in local Vitro search. This will usually consist of:
# scheme + server_name + port + vitro_webapp_name + "solr" # scheme + server_name + port + vitro_webapp_name + "solr"
@ -45,28 +32,6 @@ webapp.name = vitro
# vitro.local.solr.url = http://localhost:8080/vitrosolr # vitro.local.solr.url = http://localhost:8080/vitrosolr
vitro.local.solr.url = http://localhost:8080/vitrosolr vitro.local.solr.url = http://localhost:8080/vitrosolr
#
# Restricts access to the Solr search platform. The value is a regular expression.
# When a request is made to Solr, the IP address of the requestor must match the
# regular expression, or the request will be rejected.
#
# NOTE: don't leave a space on the end of the line, unless you want it to be
# part of the expression.
# Examples:
# vitro.local.solr.ipaddress.mask = 127\.0\.0\.1
# vitro.local.solr.ipaddress.mask = 127\.0\.0\.1|0:0:0:0:0:0:0:1
# vitro.local.solr.ipaddress.mask = 169\.254\..*
# If this line is removed, your Solr server will respond to requests from any
# location. This may be useful for experimenting but would likely be considered
# a security problem in a production environment.
vitro.local.solr.ipaddress.mask = 127\.0\.0\.1|[0:]+:1
#
# The location where the Vitro application will store the data that it creates.
# This includes uploaded files (usually images) and the search index.
#
vitro.home.directory = /usr/local/vitro/data
# #
# Email parameters which VIVO can use to send mail. If these are left empty, # Email parameters which VIVO can use to send mail. If these are left empty,
# the "Contact Us" form will be disabled and users will not be notified of # the "Contact Us" form will be disabled and users will not be notified of
@ -154,3 +119,55 @@ proxy.eligibleTypeList = http://www.w3.org/2002/07/owl#Thing
# header supplied by the browser. Default is true if not set. # header supplied by the browser. Default is true if not set.
# #
RDFService.languageFilter = true RDFService.languageFilter = true
#
# Force VIVO to use a specific language or Locale instead of those
# specified by the browser. This affects RDF data retrieved from the model,
# if RDFService.languageFilter is true. This also affects the text of pages
# that have been modified to support multiple languages.
#
# languages.forceLocale = en_US
#
# A list of supported languages or Locales that the user may choose to
# use instead of the one specified by the browser. Selection images must
# be available in the i18n/images directory of the theme. This affects
# RDF data retrieved from the model, if RDFService.languageFilter is true.
# This also affects the text of pages that have been modified to support
# multiple languages.
#
# This should not be used with languages.forceLocale, which will override it.
#
# languages.selectableLocales = en, es, fr
#
# For developers only: Setting this option to "true" slows down Vitro performance.
#
# Defeat the Freemarker template cache, so each template is read from disk
# on each request. This permits developers to immediately see the effect of
# changes to the template. The default is <code>false</code>, which means
# that a cached copy of each template will be used for 60 seconds before
# the disk is checked for a new version.
#
# developer.defeatFreemarkerCache = true
#
# For developers only: Setting this option to "true" slows down Vitro performance.
#
# Defeat the cache of language-specific text strings, so the language file
# is read from disk on each request. This permits developers to immediately
# see the effect of changes to the text strings. The default is
# <code>false</code>, which means that the language file is read when
# VIVO starts up, or when a new theme is selected.
#
# developer.defeatI18nCache = true
#
# For developers only: Setting this option to "true" slows down Vitro performance.
#
# Add starting and ending delimiters to each Freemarker template, so you can see
# which template were invoked by viewing the generated HTML. The default is
# <code>false</code>.
#
# developer.insertFreemarkerDelimiters = true

View file

@ -165,6 +165,9 @@ webapp/web/js/raphael/*
# See /doc/3rd-party-licenses.txt for LICENSE file # See /doc/3rd-party-licenses.txt for LICENSE file
webapp/web/js/sparql/prototype.js webapp/web/js/sparql/prototype.js
# See /doc/3rd-party-licenses.txt for LICENSE file
webapp/web/js/amplify/amplify.store.min.js
# Apache Solr search platform. See /doc/3rd-party-licenses.txt for LICENSE file # Apache Solr search platform. See /doc/3rd-party-licenses.txt for LICENSE file
solr/**/* solr/**/*
solr/* solr/*

View file

@ -1,20 +1,5 @@
<Context> <Context>
<!-- $This file is distributed under the terms of the license in /doc/license.txt$ --> <!-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
<!--
Vitro will interpret this as either a file path or a resource path. So,
if a simple resource path is used, such as "deploy.properties", Vitro
will find the file at:
${Tomcat}/webapps/vitro/WEB-INF/classes/deploy.properties
For an external file, specify a full file path, like
"/usr/local/vitro/deploy.properties".
-->
<Environment type="java.lang.String" override="false"
name="path.configuration"
value="deploy.properties"
/>
<!-- <!--
Disable the attempt to persist sessions when Tomcat shuts down. Disable the attempt to persist sessions when Tomcat shuts down.
--> -->

View file

@ -120,7 +120,7 @@ public class RootUserPolicy implements PolicyIface {
PROPERTY_ROOT_USER_EMAIL); PROPERTY_ROOT_USER_EMAIL);
if (email == null) { if (email == null) {
throw new IllegalStateException( throw new IllegalStateException(
"deploy.properties must contain a value for '" "runtime.properties must contain a value for '"
+ PROPERTY_ROOT_USER_EMAIL + "'"); + PROPERTY_ROOT_USER_EMAIL + "'");
} else { } else {
return email; return email;
@ -177,7 +177,7 @@ public class RootUserPolicy implements PolicyIface {
private void complainAboutMultipleRootUsers() { private void complainAboutMultipleRootUsers() {
for (String other : otherRootUsers) { for (String other : otherRootUsers) {
ss.warning(this, "deploy.properties specifies '" ss.warning(this, "runtime.properties specifies '"
+ configuredRootUser + "' as the value for '" + configuredRootUser + "' as the value for '"
+ PROPERTY_ROOT_USER_EMAIL + PROPERTY_ROOT_USER_EMAIL
+ "', but the system also contains this root user: " + "', but the system also contains this root user: "
@ -189,7 +189,7 @@ public class RootUserPolicy implements PolicyIface {
private void complainAboutWrongRootUsers() { private void complainAboutWrongRootUsers() {
for (String other : otherRootUsers) { for (String other : otherRootUsers) {
ss.warning(this, "deploy.properties specifies '" ss.warning(this, "runtime.properties specifies '"
+ configuredRootUser + "' as the value for '" + configuredRootUser + "' as the value for '"
+ PROPERTY_ROOT_USER_EMAIL + PROPERTY_ROOT_USER_EMAIL
+ "', but the system contains this root user instead: " + "', but the system contains this root user instead: "

View file

@ -49,15 +49,6 @@ public class ApplicationBean {
private String copyrightAnchor; private String copyrightAnchor;
private String themeDir; private String themeDir;
public static ApplicationBean getAppBean(ServletContext sc){
if( sc != null ){
Object obj = sc.getAttribute("applicationBean");
if( obj != null )
return (ApplicationBean)obj;
}
return new ApplicationBean();
}
public String toString() { public String toString() {
String output = "Application Bean Contents:\n"; String output = "Application Bean Contents:\n";
output += " initialized from DB: [" + initialized + "]\n"; output += " initialized from DB: [" + initialized + "]\n";

View file

@ -20,8 +20,8 @@ import org.apache.commons.logging.LogFactory;
* are attached to the servlet context. * are attached to the servlet context.
* *
* The customary behavior is for ConfigurationPropertiesSetup to create a * The customary behavior is for ConfigurationPropertiesSetup to create a
* ConfigurationPropertiesImpl, which will parse the deploy.properties file for * ConfigurationPropertiesImpl, which will obtain the properties from the
* these properties. * build.properties file and the runtime.properties file.
*/ */
public abstract class ConfigurationProperties { public abstract class ConfigurationProperties {
private static final Log log = LogFactory private static final Log log = LogFactory

View file

@ -9,13 +9,16 @@ import java.util.Enumeration;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.TreeMap;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
/** /**
* The basic implementation of ConfigurationProperties. It loads the * The basic implementation of ConfigurationProperties. It loads the
* configuration properties from a properties file and stores them in a map. * configuration properties from a properties file and stores them in a map. It
* also permits the caller to supply a map of "preemptive" properties that will
* be included and will override any matching properties from the file.
* *
* Leading and trailing white space are trimmed from the property values. * Leading and trailing white space are trimmed from the property values.
* *
@ -27,23 +30,25 @@ public class ConfigurationPropertiesImpl extends ConfigurationProperties {
private final Map<String, String> propertyMap; private final Map<String, String> propertyMap;
public ConfigurationPropertiesImpl(InputStream stream) { public ConfigurationPropertiesImpl(InputStream stream,
Map<String, String> preemptiveProperties) throws IOException {
Properties props = loadFromPropertiesFile(stream); Properties props = loadFromPropertiesFile(stream);
Map<String, String> map = copyPropertiesToMap(props); Map<String, String> map = copyPropertiesToMap(props);
trimWhiteSpaceFromValues(map);
this.propertyMap = Collections.unmodifiableMap(map);
if (preemptiveProperties != null) {
map.putAll(preemptiveProperties);
}
trimWhiteSpaceFromValues(map);
this.propertyMap = Collections.unmodifiableMap(map);
log.debug("Configuration properties are: " + map); log.debug("Configuration properties are: " + map);
} }
private Properties loadFromPropertiesFile(InputStream stream) { private Properties loadFromPropertiesFile(InputStream stream)
throws IOException {
Properties props = new Properties(); Properties props = new Properties();
try { props.load(stream);
props.load(stream);
} catch (IOException e) {
throw new IllegalStateException(
"Failed to parse the configuration properties file.", e);
}
return props; return props;
} }
@ -84,7 +89,8 @@ public class ConfigurationPropertiesImpl extends ConfigurationProperties {
@Override @Override
public String toString() { public String toString() {
return "ConfigurationPropertiesImpl[propertyMap=" + propertyMap + "]"; return "ConfigurationPropertiesImpl[propertyMap="
+ new TreeMap<String, String>(propertyMap) + "]";
} }
} }

View file

@ -4,11 +4,13 @@ package edu.cornell.mannlib.vitro.webapp.config;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext; import javax.naming.InitialContext;
import javax.naming.NamingException; import javax.naming.NamingException;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
@ -21,61 +23,45 @@ import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus; import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
/** /**
* Reads the configuration properties from a file and stores them in the servlet * Locates the runtime configuration properties and stores them in the servlet
* context. * context.
* *
* This must be invoked before any listener that requires configuration * This must be invoked before any listener that requires configuration
* properties. * properties.
* *
* The path to the file can be specified by an Environment name in the Context, * The properties file must be called 'runtime.properties' in the Vitro home
* like this: * directory. The path to the Vitro home directory can be specifed by an JNDI
* value, or by a System property, or by a property in
* WEB-INF/resources/build.properties, in that order. If the Vitro home
* directory is specified in more than one way, a warning is issued and the
* first value is used.
* *
* <pre> * If the Vitro home directory cannot be located, or if it does not contain a
* file called 'runtime.properties', or if the file cannot be loaded, a fatal
* error is registered to abort the startup.
* *
* <Context override="true"> * The ConfigurationProperties bean is created from the key/value pairs found in
* <Environment name="path.configuration" * 'runtime.properties', and is stored in the servlet context. The value that
* value="/wherever/the/file/lives/deploy.properties" * was determined for 'vitro.home' is also included in the bean.
* type="java.lang.String"
* override="false" />
* </Context>
*
* </pre>
*
* We look in this environment variable to find the path to the properties file.
* If there is no such environment variable, the default path is used.
*
* Once the path has been determined, we will use it to look for a resource in
* the classpath. So if the path is "deploy.properties", it might be found in
* "tomcat/webapps/vivo/WEB-INF/classes/deploy.properties". Of course, it might
* also be found in any other portion of the classpath as well.
*
* If we can't find the resource in the classpath, we will use it to look for an
* external file. So, one might reasonably set this value to something like
* "/usr/local/vitro/stuff/my.deploy.properties".
*
* If neither a resource nor an external file can be found, we throw an
* exception and set AbortStartup.
*/ */
public class ConfigurationPropertiesSetup implements ServletContextListener { public class ConfigurationPropertiesSetup implements ServletContextListener {
private static final Log log = LogFactory private static final Log log = LogFactory
.getLog(ConfigurationPropertiesSetup.class); .getLog(ConfigurationPropertiesSetup.class);
/** /** JNDI path that defines the Vitro home directory */
* The JNDI naming context where Tomcat stores environment attributes. private static final String VHD_JNDI_PATH = "java:comp/env/vitro/home";
*/
static final String JNDI_BASE = "java:comp/env";
/** /** System property that defines the Vitro home directory */
* The name of the JNDI environment mapping for the path to the private static final String VHD_SYSTEM_PROPERTY = "vitro.home";
* configuration file (or resource).
*/
static final String PATH_CONFIGURATION = "path.configuration";
/** /** build.properties property that defines the Vitro home directory */
* If we don't find the path to the config properties from a JNDI mapping, private static final String VHD_BUILD_PROPERTY = "vitro.home";
* use this. Not final, so we can jigger it for unit tests.
*/ /** Configuration property to store the Vitro home directory */
private static String DEFAULT_CONFIG_PATH = "deploy.properties"; private static final String VHD_CONFIGURATION_PROPERTY = "vitro.home";
/** Name of the file that contains runtime properties. */
private static final String FILE_RUNTIME_PROPERTIES = "runtime.properties";
@Override @Override
public void contextInitialized(ServletContextEvent sce) { public void contextInitialized(ServletContextEvent sce) {
@ -85,12 +71,18 @@ public class ConfigurationPropertiesSetup implements ServletContextListener {
try { try {
InputStream stream = null; InputStream stream = null;
try { try {
stream = locatePropertiesFile(); File vitroHomeDir = locateVitroHomeDirectory(ctx, ss);
File runtimePropertiesFile = locateRuntimePropertiesFile(
vitroHomeDir, ss);
stream = new FileInputStream(runtimePropertiesFile);
Map<String, String> preempts = createPreemptiveProperties(
VHD_CONFIGURATION_PROPERTY, vitroHomeDir);
ConfigurationPropertiesImpl bean = new ConfigurationPropertiesImpl( ConfigurationPropertiesImpl bean = new ConfigurationPropertiesImpl(
stream); stream, preempts);
ConfigurationProperties.setBean(ctx, bean);
ConfigurationProperties.setBean(ctx, bean);
ss.info(this, "Loaded " + bean.getPropertyMap().size() ss.info(this, "Loaded " + bean.getPropertyMap().size()
+ " properties."); + " properties.");
} finally { } finally {
@ -102,81 +94,171 @@ public class ConfigurationPropertiesSetup implements ServletContextListener {
} }
} }
} }
} catch (IllegalStateException e) {
ss.fatal(this, e.getMessage(), e);
} catch (Exception e) { } catch (Exception e) {
log.error(e, e);
ss.fatal(this, e.getMessage(), e); ss.fatal(this, e.getMessage(), e);
} }
} }
private InputStream locatePropertiesFile() {
String path = determinePathToProperties();
log.debug("Configuration properties path is '" + path + "'");
if (resourceExists(path)) {
log.debug("Found configuration properties as a resource.");
return getResourceStream(path);
}
if (externalFileExists(path)) {
log.debug("Found configuration properties as an external file.");
return getExternalFileStream(path);
}
throw new IllegalStateException("Can't find the properties file at '"
+ path + "'");
}
/** /**
* If we can't find it with JNDI, use the default. * Look in the JDNI environment, the system properties, and the
* build.properties file.
*
* If we don't find it, fail. If we find it more than once, warn and use the
* first one.
*
* Confirm that it is an existing, readable directory.
*/ */
private String determinePathToProperties() { private File locateVitroHomeDirectory(ServletContext ctx, StartupStatus ss) {
Map<String, String> whereWasIt = new LinkedHashMap<String, String>();
getVhdFromJndi(whereWasIt);
getVhdFromSystemProperties(whereWasIt);
getVhdFromBuildProperties(ctx, whereWasIt);
if (whereWasIt.isEmpty()) {
String message = String.format("Can't find a value "
+ "for the Vitro home directory. "
+ "Looked in JNDI environment at '%s'. "
+ "Looked for a system property named '%s'. "
+ "Looked in 'WEB-INF/resources/build.properties' "
+ "for '%s'.", VHD_JNDI_PATH, VHD_SYSTEM_PROPERTY,
VHD_BUILD_PROPERTY);
throw new IllegalStateException(message);
} else if (whereWasIt.size() > 1) {
String message = String.format("Found multiple values for the "
+ "Vitro home directory: " + whereWasIt.keySet());
ss.warning(this, message);
}
String message = whereWasIt.keySet().iterator().next();
String vhdPath = whereWasIt.values().iterator().next();
ss.info(this, message);
File vhd = new File(vhdPath);
if (!vhd.exists()) {
throw new IllegalStateException("Vitro home directory '" + vhdPath
+ "' does not exist.");
}
if (!vhd.isDirectory()) {
throw new IllegalStateException("Vitro home directory '" + vhdPath
+ "' is not a directory.");
}
if (!vhd.canRead()) {
throw new IllegalStateException("Vitro home directory '" + vhdPath
+ "' cannot be read.");
}
if (!vhd.canWrite()) {
throw new IllegalStateException(
"Can't write to Vitro home directory: '" + vhdPath + "'.");
}
return vhd;
}
private void getVhdFromJndi(Map<String, String> whereWasIt) {
try { try {
Context envCtx = (Context) new InitialContext().lookup(JNDI_BASE); String vhdPath = (String) new InitialContext()
if (envCtx == null) { .lookup(VHD_JNDI_PATH);
log.debug("JNDI Lookup on '" + JNDI_BASE + "' failed.");
return DEFAULT_CONFIG_PATH; if (vhdPath == null) {
log.debug("Didn't find a JNDI value at '" + VHD_JNDI_PATH
+ "'.");
return;
} }
String configPath = (String) envCtx.lookup(PATH_CONFIGURATION); log.debug("'" + VHD_JNDI_PATH + "' as specified by JNDI: "
if (configPath == null) { + vhdPath);
log.debug("JNDI Lookup on '" + PATH_CONFIGURATION + "' failed."); String message = String.format(
return DEFAULT_CONFIG_PATH; "JNDI environment '%s' was set to '%s'", VHD_JNDI_PATH,
} vhdPath);
whereWasIt.put(message, vhdPath);
log.debug("deploy.property as specified by JNDI: " + configPath);
return configPath;
} catch (NamingException e) { } catch (NamingException e) {
log.warn("JNDI lookup failed. " log.debug("JNDI lookup failed. " + e);
+ "Using default path for config properties.", e);
return DEFAULT_CONFIG_PATH;
} }
} }
private boolean resourceExists(String path) { private void getVhdFromSystemProperties(Map<String, String> whereWasIt) {
return getResourceStream(path) != null; String vhdPath = System.getProperty(VHD_SYSTEM_PROPERTY);
if (vhdPath == null) {
log.debug("Didn't find a system property value at '"
+ VHD_SYSTEM_PROPERTY + "'.");
return;
}
log.debug("'" + VHD_SYSTEM_PROPERTY
+ "' as specified by system property: " + vhdPath);
String message = String.format("System property '%s' was set to '%s'",
VHD_SYSTEM_PROPERTY, vhdPath);
whereWasIt.put(message, vhdPath);
} }
private InputStream getResourceStream(String path) { private void getVhdFromBuildProperties(ServletContext ctx,
return getClass().getClassLoader().getResourceAsStream(path); Map<String, String> whereWasIt) {
} String resourcePath = "/WEB-INF/resources/build.properties";
private boolean externalFileExists(String path) {
File file = new File(path);
return file.isFile();
}
private InputStream getExternalFileStream(String path) {
InputStream stream = null; InputStream stream = null;
File file = new File(path); try {
if (file.isFile()) { stream = ctx.getResourceAsStream(resourcePath);
try { if (stream == null) {
stream = new FileInputStream(file); log.debug("Didn't find a resource at '" + resourcePath + "'.");
} catch (FileNotFoundException e) { return;
// testing file.isFile() should have prevented this }
log.error(e, e);
Properties props = new Properties();
props.load(stream);
String vhdPath = props.getProperty(VHD_BUILD_PROPERTY);
if (vhdPath == null) {
log.debug("'" + resourcePath + "' didn't contain a value for '"
+ VHD_BUILD_PROPERTY + "'.");
return;
}
log.debug("'" + VHD_BUILD_PROPERTY
+ "' as specified by build.properties: " + vhdPath);
String message = String.format(
"In resource '%s', '%s' was set to '%s'.", resourcePath,
VHD_BUILD_PROPERTY, vhdPath);
whereWasIt.put(message, vhdPath);
} catch (IOException e) {
log.warn("Failed to load from '" + resourcePath + "'.", e);
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
} }
} }
return stream; }
private File locateRuntimePropertiesFile(File vitroHomeDir, StartupStatus ss) {
File rpf = new File(vitroHomeDir, FILE_RUNTIME_PROPERTIES);
if (!rpf.exists()) {
throw new IllegalStateException("Did not find '"
+ FILE_RUNTIME_PROPERTIES + "' in vitro home directory '"
+ vitroHomeDir + "'");
}
if (!rpf.isFile()) {
throw new IllegalStateException("'" + rpf.getPath()
+ "' is not a file.");
}
if (!rpf.canRead()) {
throw new IllegalStateException("Cannot read '" + rpf.getPath()
+ "'.");
}
ss.info(this, "Loading runtime properties from '" + rpf.getPath() + "'");
return rpf;
}
private Map<String, String> createPreemptiveProperties(
String propertyVitroHome, File vitroHomeDir) {
Map<String, String> map = new HashMap<String, String>();
map.put(propertyVitroHome, vitroHomeDir.getAbsolutePath());
return map;
} }
@Override @Override

View file

@ -32,7 +32,7 @@ public class ConfigurationPropertiesSmokeTests implements
private static final Log log = LogFactory private static final Log log = LogFactory
.getLog(ConfigurationPropertiesSmokeTests.class); .getLog(ConfigurationPropertiesSmokeTests.class);
private static final String PROPERTY_HOME_DIRECTORY = "vitro.home.directory"; private static final String PROPERTY_HOME_DIRECTORY = "vitro.home";
private static final String PROPERTY_DB_URL = "VitroConnection.DataSource.url"; private static final String PROPERTY_DB_URL = "VitroConnection.DataSource.url";
private static final String PROPERTY_DB_USERNAME = "VitroConnection.DataSource.username"; private static final String PROPERTY_DB_USERNAME = "VitroConnection.DataSource.username";
private static final String PROPERTY_DB_PASSWORD = "VitroConnection.DataSource.password"; private static final String PROPERTY_DB_PASSWORD = "VitroConnection.DataSource.password";
@ -61,7 +61,7 @@ public class ConfigurationPropertiesSmokeTests implements
ConfigurationProperties props, StartupStatus ss) { ConfigurationProperties props, StartupStatus ss) {
String homeDirectoryPath = props.getProperty(PROPERTY_HOME_DIRECTORY); String homeDirectoryPath = props.getProperty(PROPERTY_HOME_DIRECTORY);
if (homeDirectoryPath == null || homeDirectoryPath.isEmpty()) { if (homeDirectoryPath == null || homeDirectoryPath.isEmpty()) {
ss.fatal(this, "deploy.properties does not contain a value for '" ss.fatal(this, "Can't find a value for the home directory: '"
+ PROPERTY_HOME_DIRECTORY + "'"); + PROPERTY_HOME_DIRECTORY + "'");
return; return;
} }
@ -97,19 +97,19 @@ public class ConfigurationPropertiesSmokeTests implements
ConfigurationProperties props, StartupStatus ss) { ConfigurationProperties props, StartupStatus ss) {
String url = props.getProperty(PROPERTY_DB_URL); String url = props.getProperty(PROPERTY_DB_URL);
if (url == null || url.isEmpty()) { if (url == null || url.isEmpty()) {
ss.fatal(this, "deploy.properties does not contain a value for '" ss.fatal(this, "runtime.properties does not contain a value for '"
+ PROPERTY_DB_URL + "'"); + PROPERTY_DB_URL + "'");
return; return;
} }
String username = props.getProperty(PROPERTY_DB_USERNAME); String username = props.getProperty(PROPERTY_DB_USERNAME);
if (username == null || username.isEmpty()) { if (username == null || username.isEmpty()) {
ss.fatal(this, "deploy.properties does not contain a value for '" ss.fatal(this, "runtime.properties does not contain a value for '"
+ PROPERTY_DB_USERNAME + "'"); + PROPERTY_DB_USERNAME + "'");
return; return;
} }
String password = props.getProperty(PROPERTY_DB_PASSWORD); String password = props.getProperty(PROPERTY_DB_PASSWORD);
if (password == null || password.isEmpty()) { if (password == null || password.isEmpty()) {
ss.fatal(this, "deploy.properties does not contain a value for '" ss.fatal(this, "runtime.properties does not contain a value for '"
+ PROPERTY_DB_PASSWORD + "'"); + PROPERTY_DB_PASSWORD + "'");
return; return;
} }
@ -259,7 +259,7 @@ public class ConfigurationPropertiesSmokeTests implements
ConfigurationProperties props, StartupStatus ss) { ConfigurationProperties props, StartupStatus ss) {
String ns = props.getProperty(PROPERTY_DEFAULT_NAMESPACE); String ns = props.getProperty(PROPERTY_DEFAULT_NAMESPACE);
if (ns == null || ns.isEmpty()) { if (ns == null || ns.isEmpty()) {
ss.fatal(this, "deploy.properties does not contain a value for '" ss.fatal(this, "runtime.properties does not contain a value for '"
+ PROPERTY_DEFAULT_NAMESPACE + "'"); + PROPERTY_DEFAULT_NAMESPACE + "'");
return; return;
} }

View file

@ -33,9 +33,6 @@ import edu.cornell.mannlib.vitro.webapp.web.ContentType;
public class OntologyController extends VitroHttpServlet{ public class OntologyController extends VitroHttpServlet{
private static final Log log = LogFactory.getLog(OntologyController.class.getName()); private static final Log log = LogFactory.getLog(OntologyController.class.getName());
private String default_jsp = Controllers.BASIC_JSP;
private ApplicationBean appBean;
public void doPost(HttpServletRequest request, HttpServletResponse response) public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException,IOException{ throws ServletException,IOException{
doGet(request, response); doGet(request, response);
@ -242,7 +239,7 @@ public class OntologyController extends VitroHttpServlet{
throws IOException, ServletException { throws IOException, ServletException {
VitroRequest vreq = new VitroRequest(req); VitroRequest vreq = new VitroRequest(req);
ApplicationBean appBean = ApplicationBean.getAppBean(getServletContext()); ApplicationBean appBean = vreq.getAppBean();
//set title before we do the highlighting so we don't get markup in it. //set title before we do the highlighting so we don't get markup in it.
req.setAttribute("title","not found"); req.setAttribute("title","not found");

View file

@ -283,12 +283,8 @@ public class VitroRequest extends HttpServletRequestWrapper {
} }
public ApplicationBean getAppBean(){ public ApplicationBean getAppBean(){
//return (ApplicationBean) getAttribute("appBean");
return getWebappDaoFactory().getApplicationDao().getApplicationBean(); return getWebappDaoFactory().getApplicationDao().getApplicationBean();
} }
public void setAppBean(ApplicationBean ab){
setAttribute("appBean",ab);
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override

View file

@ -7,7 +7,6 @@ import java.util.Map;
import edu.cornell.mannlib.vitro.webapp.auth.permissions.SimplePermission; import edu.cornell.mannlib.vitro.webapp.auth.permissions.SimplePermission;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions;
import edu.cornell.mannlib.vitro.webapp.beans.ApplicationBean;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServlet; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServlet;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
@ -31,7 +30,7 @@ public class StartupStatusController extends FreemarkerHttpServlet {
body.put("title", "Startup Status"); body.put("title", "Startup Status");
body.put("status", StartupStatus.getBean(getServletContext())); body.put("status", StartupStatus.getBean(getServletContext()));
body.put("contextPath", getContextPath()); body.put("contextPath", getContextPath());
body.put("applicationName", getApplicationName()); body.put("applicationName", getApplicationName(vreq));
return new TemplateResponseValues("startupStatus-display.ftl", body); return new TemplateResponseValues("startupStatus-display.ftl", body);
} }
@ -45,11 +44,10 @@ public class StartupStatusController extends FreemarkerHttpServlet {
} }
} }
private Object getApplicationName() { private Object getApplicationName(VitroRequest vreq) {
String name = ""; String name = "";
try { try {
ApplicationBean app = ApplicationBean.getAppBean(getServletContext()); name = vreq.getAppBean().getApplicationName();
name = app.getApplicationName();
} catch (Exception e) { } catch (Exception e) {
// deal with problems below // deal with problems below
} }

View file

@ -117,7 +117,7 @@ public class ExternalAuthHelper {
} }
if (externalAuthServerUrl == null) { if (externalAuthServerUrl == null) {
log.debug("deploy.properties doesn't contain a value for '" log.debug("runtime.properties doesn't contain a value for '"
+ PROPERTY_EXTERNAL_AUTH_SERVER_URL + PROPERTY_EXTERNAL_AUTH_SERVER_URL
+ "' -- sending directly to '" + returnUrl + "'"); + "' -- sending directly to '" + returnUrl + "'");
return returnUrl; return returnUrl;
@ -142,7 +142,7 @@ public class ExternalAuthHelper {
if (externalAuthHeaderName == null) { if (externalAuthHeaderName == null) {
log.error("User asked for external authentication, " log.error("User asked for external authentication, "
+ "but deploy.properties doesn't contain a value for '" + "but runtime.properties doesn't contain a value for '"
+ PROPERTY_EXTERNAL_AUTH_ID_HEADER + "'"); + PROPERTY_EXTERNAL_AUTH_ID_HEADER + "'");
return null; return null;
} }

View file

@ -37,7 +37,7 @@ public class LoginExternalAuthReturn extends BaseLoginServlet {
* the header will contain the name of the user who just logged in. * the header will contain the name of the user who just logged in.
* *
* Deal with these possibilities: * Deal with these possibilities:
* - The header name was not configured in deploy.properties. Complain. * - The header name was not configured in runtime.properties. Complain.
* - No username: the login failed. Complain * - No username: the login failed. Complain
* - User corresponds to a User acocunt. Record the login. * - User corresponds to a User acocunt. Record the login.
* - User corresponds to an Individual (self-editor). * - User corresponds to an Individual (self-editor).

View file

@ -50,7 +50,7 @@ public class ContactMailController extends FreemarkerHttpServlet {
private final static String TEMPLATE_ERROR = "contactForm-error.ftl"; private final static String TEMPLATE_ERROR = "contactForm-error.ftl";
private final static String TEMPLATE_FORM = "contactForm-form.ftl"; private final static String TEMPLATE_FORM = "contactForm-form.ftl";
private static final String PROPERTY_VITRO_HOME_DIR = "vitro.home.directory"; private static final String PROPERTY_VITRO_HOME_DIR = "vitro.home";
private static final String EMAIL_JOURNAL_FILE_DIR = "emailJournal"; private static final String EMAIL_JOURNAL_FILE_DIR = "emailJournal";
private static final String EMAIL_JOURNAL_FILE_NAME = "contactFormEmails.html"; private static final String EMAIL_JOURNAL_FILE_NAME = "contactFormEmails.html";

View file

@ -0,0 +1,126 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.controller.freemarker;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import freemarker.cache.TemplateLoader;
/**
* Wrap a TemplateLoader, so each time a template is read, delimiters will be
* inserted at the beginning and end. This makes it easier for a developer can
* see what lines of HTML come from which templates.
*
* TemplateLoader returns a token object when finding a template, and then
* recognizes that object when it is used as an argument to getLastModified() or
* getReader(). In order to keep track of the template name, we wrap the token
* object and the name in a token of our own.
*
* Taking the easy way out and reading in the entire template into a string.
* This limits the template size to less than 2^31 characters (~2 GBytes). That
* seems adequate.
*/
public class DelimitingTemplateLoader implements TemplateLoader {
private static final Log log = LogFactory
.getLog(DelimitingTemplateLoader.class);
private final TemplateLoader innerLoader;
public DelimitingTemplateLoader(TemplateLoader innerLoader) {
this.innerLoader = innerLoader;
}
@Override
public Object findTemplateSource(String name) throws IOException {
Object innerTS = innerLoader.findTemplateSource(name);
if (innerTS == null) {
return null;
} else {
return new DelimitingTemplateSource(name, innerTS);
}
}
@Override
public long getLastModified(Object templateSource) {
DelimitingTemplateSource dts = (DelimitingTemplateSource) templateSource;
return innerLoader.getLastModified(dts.ts);
}
@Override
public Reader getReader(Object templateSource, String encoding)
throws IOException {
DelimitingTemplateSource dts = (DelimitingTemplateSource) templateSource;
StringBuilder sb = new StringBuilder();
sb.append("<!-- FM_BEGIN ").append(dts.name).append(" -->");
sb.append(readTemplateSource(encoding, dts.ts));
sb.append("<!-- FM_END ").append(dts.name).append(" -->\n");
return new StringReader(sb.toString());
}
private StringBuilder readTemplateSource(String encoding, Object ts)
throws IOException {
StringBuilder sb = new StringBuilder();
Reader reader = innerLoader.getReader(ts, encoding);
char[] buffer = new char[8192];
int howmany;
while (-1 != (howmany = reader.read(buffer))) {
sb.append(buffer, 0, howmany);
}
return sb;
}
@Override
public void closeTemplateSource(Object templateSource) throws IOException {
DelimitingTemplateSource dts = (DelimitingTemplateSource) templateSource;
innerLoader.closeTemplateSource(dts.ts);
}
// ----------------------------------------------------------------------
// Helper classes
// ----------------------------------------------------------------------
/**
* Data object, wrapping the template name and the templateSource object
* from the inner TemplateLoader.
*/
private static class DelimitingTemplateSource {
public final String name;
public final Object ts;
public DelimitingTemplateSource(String name, Object ts) {
if (name == null) {
throw new NullPointerException("name may not be null.");
}
if (ts == null) {
throw new NullPointerException("ts may not be null.");
}
this.name = name;
this.ts = ts;
}
@Override
public int hashCode() {
return name.hashCode() ^ ts.hashCode();
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (o == null) {
return false;
}
if (!o.getClass().equals(this.getClass())) {
return false;
}
DelimitingTemplateSource that = (DelimitingTemplateSource) o;
return this.name.equals(that.name) && this.ts.equals(that.ts);
}
}
}

View file

@ -6,10 +6,14 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Set;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@ -17,8 +21,12 @@ import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.beans.ApplicationBean; import edu.cornell.mannlib.vitro.webapp.beans.ApplicationBean;
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties; import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
import edu.cornell.mannlib.vitro.webapp.config.RevisionInfoBean; import edu.cornell.mannlib.vitro.webapp.config.RevisionInfoBean;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Route; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Route;
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.EditConfigurationConstants; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.EditConfigurationConstants;
import edu.cornell.mannlib.vitro.webapp.i18n.freemarker.I18nMethodModel;
import edu.cornell.mannlib.vitro.webapp.utils.dataGetter.DataGetter;
import edu.cornell.mannlib.vitro.webapp.utils.dataGetter.DataGetterUtils;
import edu.cornell.mannlib.vitro.webapp.web.directives.IndividualShortViewDirective; import edu.cornell.mannlib.vitro.webapp.web.directives.IndividualShortViewDirective;
import edu.cornell.mannlib.vitro.webapp.web.methods.IndividualLocalNameMethod; import edu.cornell.mannlib.vitro.webapp.web.methods.IndividualLocalNameMethod;
import edu.cornell.mannlib.vitro.webapp.web.methods.IndividualPlaceholderImageUrlMethod; import edu.cornell.mannlib.vitro.webapp.web.methods.IndividualPlaceholderImageUrlMethod;
@ -27,30 +35,38 @@ import freemarker.cache.ClassTemplateLoader;
import freemarker.cache.FileTemplateLoader; import freemarker.cache.FileTemplateLoader;
import freemarker.cache.MultiTemplateLoader; import freemarker.cache.MultiTemplateLoader;
import freemarker.cache.TemplateLoader; import freemarker.cache.TemplateLoader;
import freemarker.core.Environment;
import freemarker.ext.beans.BeansWrapper; import freemarker.ext.beans.BeansWrapper;
import freemarker.template.Configuration; import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper; import freemarker.template.DefaultObjectWrapper;
import freemarker.template.ObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateException; import freemarker.template.TemplateException;
import freemarker.template.TemplateModelException; import freemarker.template.TemplateModelException;
import freemarker.template.utility.DeepUnwrap;
public class FreemarkerConfiguration extends Configuration { public class FreemarkerConfiguration extends Configuration {
private static final Log log = LogFactory.getLog(FreemarkerConfiguration.class); private static final Log log = LogFactory.getLog(FreemarkerConfiguration.class);
private final String themeDir; private static final String PROPERTY_DEVELOPER_DEFEAT_CACHE = "developer.defeatFreemarkerCache";
private static final String PROPERTY_DEVELOPER_INSERT_DELIMITERS = "developer.insertFreemarkerDelimiters";
private final String themeDir;
private final ServletContext context; private final ServletContext context;
private final ApplicationBean appBean; private final ApplicationBean appBean;
private final ConfigurationProperties props;
FreemarkerConfiguration(String themeDir, ApplicationBean appBean, ServletContext context) { FreemarkerConfiguration(String themeDir, ApplicationBean appBean, ServletContext context) {
this.themeDir = themeDir; this.themeDir = themeDir;
this.context = context; this.context = context;
this.appBean = appBean; this.appBean = appBean;
this.props = ConfigurationProperties.getBean(context);
String buildEnv = ConfigurationProperties.getBean(context).getProperty("Environment.build"); String flag = props.getProperty(PROPERTY_DEVELOPER_DEFEAT_CACHE, "false");
log.debug("Current build environment: " + buildEnv); if (Boolean.valueOf(flag.trim())) {
if ("development".equals(buildEnv)) { // Set Environment.build = development in deploy.properties log.debug("Disabling Freemarker template caching in development build.");
log.debug("Disabling Freemarker template caching in development build.");
setTemplateUpdateDelay(0); // no template caching in development setTemplateUpdateDelay(0); // no template caching in development
} else { } else {
int delay = 60; int delay = 60;
@ -164,6 +180,7 @@ public class FreemarkerConfiguration extends Configuration {
map.put("profileUrl", new IndividualProfileUrlMethod()); map.put("profileUrl", new IndividualProfileUrlMethod());
map.put("localName", new IndividualLocalNameMethod()); map.put("localName", new IndividualLocalNameMethod());
map.put("placeholderImageUrl", new IndividualPlaceholderImageUrlMethod()); map.put("placeholderImageUrl", new IndividualPlaceholderImageUrlMethod());
map.put("i18n", new I18nMethodModel());
return map; return map;
} }
@ -196,7 +213,110 @@ public class FreemarkerConfiguration extends Configuration {
log.error("Error creating template loaders"); log.error("Error creating template loaders");
} }
return mtl; // Add the ability to add delimiters to the templates, based on
// settings.
if (Boolean.valueOf(props.getProperty(PROPERTY_DEVELOPER_INSERT_DELIMITERS))) {
return new DelimitingTemplateLoader(mtl);
} else {
return mtl;
}
} }
/**
* Override getTemplate(), so we can apply DataGetters to all included
* templates.
*
* This won't work for top-level Templates, since the Environment hasn't
* been created yet. When TemplateProcessingHelper creates the Environment,
* it must call retrieveAndRunDataGetters() for the top-level Template.
*/
@Override
public Template getTemplate(String name, Locale locale, String encoding,
boolean parse) throws IOException {
Template template = super.getTemplate(name, locale, encoding, parse);
if (template == null) {
log.debug("Template '" + name + "' not found for locale '" + locale + "'.");
return template;
}
Environment env = getEnvironment();
if (env == null) {
log.debug("Not fetching data getters for template '" + template.getName() + "'. No environment.");
return template;
}
retrieveAndRunDataGetters(env, template.getName());
return template;
}
/**
* Find the DataGetters for this template, and apply them to the Freemarker
* environment.
*/
public static void retrieveAndRunDataGetters(Environment env, String templateName) {
HttpServletRequest req = (HttpServletRequest) env.getCustomAttribute("request");
VitroRequest vreq = new VitroRequest(req);
if (dataGettersAlreadyApplied(env, templateName)) {
log.debug("DataGetters for '" + templateName+"' have already been applied");
return;
}
try {
List<DataGetter> dgList = DataGetterUtils.getDataGettersForTemplate(
vreq, vreq.getDisplayModel(), templateName);
log.debug("Retrieved " + dgList.size() + " data getters for template '" + templateName + "'");
@SuppressWarnings("unchecked")
Map<String, Object> dataMap = (Map<String, Object>) DeepUnwrap.permissiveUnwrap(env.getDataModel());
for (DataGetter dg : dgList) {
applyDataGetter(dg, env, dataMap);
}
} catch (Exception e) {
log.warn(e, e);
}
}
/**
* Have the DataGetters for this template already been applied to this environment?
* If not, record that they are being applied now.
*/
@SuppressWarnings("unchecked")
private static boolean dataGettersAlreadyApplied(Environment env, String templateName) {
Set<String> names;
Object o = env.getCustomAttribute("dataGettersApplied");
if (o instanceof Set) {
names = (Set<String>) o;
} else {
names = new HashSet<String>();
}
boolean added = names.add(templateName);
if (added) {
env.setCustomAttribute("dataGettersApplied", names);
return false;
} else {
return true;
}
}
/**
* Get the data from a DataGetter, and store it in global variables in the
* Freemarker environment.
*/
private static void applyDataGetter(DataGetter dg, Environment env,
Map<String, Object> dataMap) throws TemplateModelException {
Map<String, Object> moreData = dg.getData(dataMap);
ObjectWrapper wrapper = env.getObjectWrapper();
if (moreData != null) {
for (String key : moreData.keySet()) {
Object value = moreData.get(key);
env.setGlobalVariable(key, wrapper.wrap(value));
log.debug("Stored in environment: '" + key + "' = '" + value + "'");
}
}
}
} }

View file

@ -51,12 +51,20 @@ public class TemplateProcessingHelper {
env.setCustomAttribute("request", request); env.setCustomAttribute("request", request);
env.setCustomAttribute("context", context); env.setCustomAttribute("context", context);
// Set the Locale from the request into the environment, so date builtins will be
// Locale-dependent
env.setLocale(request.getLocale());
// Define a setup template to be included by every page template // Define a setup template to be included by every page template
String templateType = (String) map.get("templateType"); String templateType = (String) map.get("templateType");
if (FreemarkerHttpServlet.PAGE_TEMPLATE_TYPE.equals(templateType)) { if (FreemarkerHttpServlet.PAGE_TEMPLATE_TYPE.equals(templateType)) {
env.include(getTemplate("pageSetup.ftl")); env.include(getTemplate("pageSetup.ftl"));
} }
// Apply any data-getters that are associated with this template.
FreemarkerConfiguration.retrieveAndRunDataGetters(env, template.getName());
// Now process it.
env.process(); env.process();
} catch (TemplateException e) { } catch (TemplateException e) {
throw new TemplateProcessingException("TemplateException creating processing environment", e); throw new TemplateProcessingException("TemplateException creating processing environment", e);

View file

@ -5,7 +5,8 @@ package edu.cornell.mannlib.vitro.webapp.controller.freemarker;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.URLDecoder; import java.net.URLDecoder;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.util.HashMap; //import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -129,7 +130,7 @@ public class UrlBuilder {
return getUrl(Route.LOGOUT); return getUrl(Route.LOGOUT);
} }
public static class ParamMap extends HashMap<String, String> { public static class ParamMap extends LinkedHashMap<String, String> {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public ParamMap() { } public ParamMap() { }
@ -276,7 +277,7 @@ public class UrlBuilder {
} }
if (profileUrl != null) { if (profileUrl != null) {
HashMap<String, String> specialParams = getModelParams(vreq); LinkedHashMap<String, String> specialParams = getModelParams(vreq);
if(specialParams.size() != 0) { if(specialParams.size() != 0) {
profileUrl = addParams(profileUrl, new ParamMap(specialParams)); profileUrl = addParams(profileUrl, new ParamMap(specialParams));
} }
@ -325,9 +326,9 @@ public class UrlBuilder {
//To be used in different property templates so placing method for reuse here //To be used in different property templates so placing method for reuse here
//Check if special params included, specifically for menu management and other models //Check if special params included, specifically for menu management and other models
public static HashMap<String,String> getModelParams(VitroRequest vreq) { public static LinkedHashMap<String,String> getModelParams(VitroRequest vreq) {
HashMap<String,String> specialParams = new HashMap<String, String>(); LinkedHashMap<String,String> specialParams = new LinkedHashMap<String, String>();
if(vreq != null) { if(vreq != null) {
//this parameter is sufficient to switch to menu model //this parameter is sufficient to switch to menu model
String useMenuModelParam = vreq.getParameter(DisplayVocabulary.SWITCH_TO_DISPLAY_MODEL); String useMenuModelParam = vreq.getParameter(DisplayVocabulary.SWITCH_TO_DISPLAY_MODEL);

View file

@ -201,7 +201,7 @@ public class JSONReconcileServlet extends VitroHttpServlet {
viewJson.put("url", urlBuf.toString() + "/individual?uri={{id}}"); viewJson.put("url", urlBuf.toString() + "/individual?uri={{id}}");
json.put("view", viewJson); json.put("view", viewJson);
// parse defaultTypeList from deploy.properties // parse defaultTypeList from runtime.properties
if (defaultTypeList != null) { if (defaultTypeList != null) {
String[] splitList = defaultTypeList.split(";"); String[] splitList = defaultTypeList.split(";");
String[][] idNameArray = new String[splitList.length][splitList.length]; String[][] idNameArray = new String[splitList.length][splitList.length];

View file

@ -15,12 +15,6 @@ public interface IndividualRequestAnalysisContext {
*/ */
String getDefaultNamespace(); String getDefaultNamespace();
/**
* Is there a namespace for this prefix? If not, return an empty string, but
* never null.
*/
String getNamespaceForPrefix(String prefix);
/** /**
* Use the IndividualDao to get this individual. * Use the IndividualDao to get this individual.
* *

View file

@ -15,8 +15,6 @@ import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.dao.IndividualDao; import edu.cornell.mannlib.vitro.webapp.dao.IndividualDao;
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
import edu.cornell.mannlib.vitro.webapp.filestorage.model.FileInfo; import edu.cornell.mannlib.vitro.webapp.filestorage.model.FileInfo;
import edu.cornell.mannlib.vitro.webapp.utils.NamespaceMapper;
import edu.cornell.mannlib.vitro.webapp.utils.NamespaceMapperFactory;
/** /**
* Implement all of the fiddly-bits that we need for analyzing the request for * Implement all of the fiddly-bits that we need for analyzing the request for
@ -45,25 +43,6 @@ public class IndividualRequestAnalysisContextImpl implements
return wadf.getDefaultNamespace(); return wadf.getDefaultNamespace();
} }
@Override
public String getNamespaceForPrefix(String prefix) {
if (prefix == null) {
return "";
}
NamespaceMapper namespaceMapper = NamespaceMapperFactory
.getNamespaceMapper(ctx);
if (namespaceMapper == null) {
log.warn("No NamespaceMapper in ServletContext. Request URL was '"
+ vreq.getRequestURL() + "'");
return "";
}
String ns = namespaceMapper.getNamespaceForPrefix(prefix);
return (ns == null) ? "" : ns;
}
@Override @Override
public Individual getIndividualByURI(String individualUri) { public Individual getIndividualByURI(String individualUri) {
if (individualUri == null) { if (individualUri == null) {

View file

@ -30,7 +30,6 @@ public class IndividualRequestAnalyzer {
private static Pattern RDF_REQUEST = Pattern.compile("^/individual/([^/]+)/\\1\\.(rdf|n3|ttl)$"); private static Pattern RDF_REQUEST = Pattern.compile("^/individual/([^/]+)/\\1\\.(rdf|n3|ttl)$");
private static Pattern HTML_REQUEST = Pattern.compile("^/display/([^/]+)$"); private static Pattern HTML_REQUEST = Pattern.compile("^/display/([^/]+)$");
private static Pattern LINKED_DATA_URL = Pattern.compile("^/individual/([^/]+)$"); private static Pattern LINKED_DATA_URL = Pattern.compile("^/individual/([^/]+)$");
private static Pattern NS_PREFIX_URL = Pattern.compile("^/individual/([^/]*)/([^/]+)$");
private final VitroRequest vreq; private final VitroRequest vreq;
private final IndividualRequestAnalysisContext analysisContext; private final IndividualRequestAnalysisContext analysisContext;
@ -164,7 +163,6 @@ public class IndividualRequestAnalyzer {
* /individual/localname/localname.rdf * /individual/localname/localname.rdf
* /individual/localname/localname.n3 * /individual/localname/localname.n3
* /individual/localname/localname.ttl * /individual/localname/localname.ttl
* /individual/nsprefix/localname
* </pre> * </pre>
* *
* @return null on failure. * @return null on failure.
@ -202,14 +200,6 @@ public class IndividualRequestAnalyzer {
return getIndividualByLocalname(rdfMatch.group(1)); return getIndividualByLocalname(rdfMatch.group(1));
} }
// Does the URL look like a namespace prefix followed by a local
// name?
Matcher prefix_match = NS_PREFIX_URL.matcher(url);
if (prefix_match.matches() && prefix_match.groupCount() == 2) {
return getIndividualByPrefixAndLocalname(prefix_match.group(1),
prefix_match.group(2));
}
// Couldn't match it to anything. // Couldn't match it to anything.
return null; return null;
} catch (Throwable e) { } catch (Throwable e) {
@ -299,12 +289,6 @@ public class IndividualRequestAnalyzer {
return getIndividualByUri(uri); return getIndividualByUri(uri);
} }
private Individual getIndividualByPrefixAndLocalname(String prefix,
String localName) {
String ns = analysisContext.getNamespaceForPrefix(prefix);
return getIndividualByUri(ns + localName);
}
private Individual getIndividualByNetId(String netId) { private Individual getIndividualByNetId(String netId) {
return analysisContext.getIndividualByNetId(netId); return analysisContext.getIndividualByNetId(netId);
} }

View file

@ -82,6 +82,7 @@ class IndividualResponseBuilder {
body.put("relatedSubject", getRelatedSubject()); body.put("relatedSubject", getRelatedSubject());
body.put("namespaces", namespaces); body.put("namespaces", namespaces);
body.put("temporalVisualizationEnabled", getTemporalVisualizationFlag()); body.put("temporalVisualizationEnabled", getTemporalVisualizationFlag());
body.put("profilePageTypesEnabled", getprofilePageTypesFlag());
body.put("verbosePropertySwitch", getVerbosePropertyValues()); body.put("verbosePropertySwitch", getVerbosePropertyValues());
//Execute data getters that might apply to this individual, e.g. because of the class of the individual //Execute data getters that might apply to this individual, e.g. because of the class of the individual
@ -91,6 +92,13 @@ class IndividualResponseBuilder {
log.error("Data retrieval for individual lead to error", ex); log.error("Data retrieval for individual lead to error", ex);
} }
// for quick profile view - users can toggle between the quick and the full views,
// so the "destination" let's us know which view they are targeting. On normal
// page request, this string is empty and the default template is loaded.
String targetedView = "";
targetedView = vreq.getParameter("destination");
body.put("targetedView", targetedView);
//Individual template model //Individual template model
IndividualTemplateModel itm = getIndividualTemplateModel(individual); IndividualTemplateModel itm = getIndividualTemplateModel(individual);
/* We need to expose non-getters in displaying the individual's property list, /* We need to expose non-getters in displaying the individual's property list,
@ -100,6 +108,7 @@ class IndividualResponseBuilder {
*/ */
// body.put("individual", wrap(itm, BeansWrapper.EXPOSE_SAFE)); // body.put("individual", wrap(itm, BeansWrapper.EXPOSE_SAFE));
body.put("labelCount", getLabelCount(itm.getUri(), vreq)); body.put("labelCount", getLabelCount(itm.getUri(), vreq));
body.put("profileType", getProfileType(itm.getUri(), vreq));
body.put("individual", wrap(itm, new ReadOnlyBeansWrapper())); body.put("individual", wrap(itm, new ReadOnlyBeansWrapper()));
body.put("headContent", getRdfLinkTag(itm)); body.put("headContent", getRdfLinkTag(itm));
@ -169,6 +178,12 @@ class IndividualResponseBuilder {
return "enabled".equals(property); return "enabled".equals(property);
} }
private boolean getprofilePageTypesFlag() {
String property = ConfigurationProperties.getBean(vreq).getProperty(
"MultiViews.profilePageTypes");
return "enabled".equals(property);
}
private Map<String, Object> getVerbosePropertyValues() { private Map<String, Object> getVerbosePropertyValues() {
Map<String, Object> map = null; Map<String, Object> map = null;
@ -275,4 +290,29 @@ class IndividualResponseBuilder {
} }
return theCount; return theCount;
} }
private static String PROFILE_TYPE_QUERY = ""
+ "PREFIX display: <http://vitro.mannlib.cornell.edu/ontologies/display/1.1#> \n"
+ "SELECT ?profile WHERE { \n"
+ " ?subject display:hasDefaultProfilePageType ?profile \n"
+ "}" ;
private static String getProfileType(String subjectUri, VitroRequest vreq) {
String queryStr = QueryUtils.subUriForQueryVar(PROFILE_TYPE_QUERY, "subject", subjectUri);
log.debug("queryStr = " + queryStr);
String profileType = "none";
try {
ResultSet results = QueryUtils.getQueryResults(queryStr, vreq);
if (results.hasNext()) {
QuerySolution soln = results.nextSolution();
String profileStr = soln.get("profile").toString();
if ( profileStr.length() > 0 ) {
profileType = profileStr.substring(profileStr.indexOf("#")+1,profileStr.length());
}
}
} catch (Exception e) {
log.error(e, e);
}
return profileType;
}
} }

View file

@ -2,7 +2,9 @@
package edu.cornell.mannlib.vitro.webapp.controller.json; package edu.cornell.mannlib.vitro.webapp.controller.json;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
@ -24,7 +26,7 @@ import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.Individual
* Does a Solr search for individuals, and uses the short view to render each of * Does a Solr search for individuals, and uses the short view to render each of
* the results. * the results.
*/ */
public class GetRenderedSolrIndividualsByVClass extends JsonObjectProducer { public class GetRenderedSolrIndividualsByVClass extends GetSolrIndividualsByVClasses {
private static final Log log = LogFactory private static final Log log = LogFactory
.getLog(GetRenderedSolrIndividualsByVClass.class); .getLog(GetRenderedSolrIndividualsByVClass.class);
@ -33,22 +35,35 @@ public class GetRenderedSolrIndividualsByVClass extends JsonObjectProducer {
} }
/** /**
* Search for individuals by VClass. The class URI and the paging * Search for individuals by VClass or VClasses in the case of multiple parameters. The class URI(s) and the paging
* information are in the request parameters. * information are in the request parameters.
*/ */
@Override @Override
protected JSONObject process() throws Exception { protected JSONObject process() throws Exception {
JSONObject rObj = null; JSONObject rObj = null;
VClass vclass = getVclassParameter(vreq);
String vclassId = vclass.getURI();
//This gets the first vclass value and sets that as display type
List<String> vclassIds = super.getVclassIds(vreq);
String vclassId = null;
if(vclassIds.size() > 1) {
//This ensures the second class instead of the first
//This is a temporary fix in cases where institutional internal classes are being sent in
//and thus the second class is the actual class with display information associated
vclassId = vclassIds.get(1);
} else {
vclassId = vclassIds.get(0);
}
vreq.setAttribute("displayType", vclassId); vreq.setAttribute("displayType", vclassId);
rObj = JsonServlet.getSolrIndividualsByVClass(vclassId, vreq, ctx);
addShortViewRenderings(rObj);
//This will get all the solr individuals by VClass (if one value) or the intersection
//i.e. individuals that have all the types for the different vclasses entered
rObj = super.process();
addShortViewRenderings(rObj);
return rObj; return rObj;
} }
//Get
/** /**
* Look through the return object. For each individual, render the short * Look through the return object. For each individual, render the short
* view and insert the resulting HTML into the object. * view and insert the resulting HTML into the object.

View file

@ -1,197 +0,0 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.controller.login;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vedit.beans.LoginStatusBean;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.edit.Authenticate;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServlet;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.TemplateProcessingHelper.TemplateProcessingException;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues;
import edu.cornell.mannlib.vitro.webapp.controller.login.LoginProcessBean.State;
/**
* A temporary means of displaying the Login templates within the SiteAdmin
* form.
*
* This class contains stuff that I swiped from {@link Authenticate}. The base
* class, {@link LoginTemplateHelperBase}, contains stuff that I swiped from
* {@link FreemarkerHttpServlet}.
*/
public class LoginTemplateHelper extends LoginTemplateHelperBase {
private static final Log log = LogFactory.getLog(LoginTemplateHelper.class);
/** If they are logging in, show them this form. */
public static final String TEMPLATE_LOGIN = "login-form.ftl";
/** If they are changing their password on first login, show them this form. */
public static final String TEMPLATE_FORCE_PASSWORD_CHANGE = "login-forcedPasswordChange.ftl";
/** Show error message */
public static final String TEMPLATE_SERVER_ERROR = Template.ERROR_MESSAGE.toString();
public static final String BODY_LOGIN_NAME = "loginName";
public static final String BODY_FORM_ACTION = "formAction";
public static final String BODY_INFO_MESSAGE = "infoMessage";
public static final String BODY_ERROR_MESSAGE = "errorMessage";
public static final String BODY_CANCEL_URL = "cancelUrl";
public LoginTemplateHelper(HttpServletRequest req) {
super(req);
}
/** Version for JSP page */
public String showLoginPage(HttpServletRequest request) {
VitroRequest vreq = new VitroRequest(request);
try {
State state = getCurrentLoginState(vreq);
log.debug("State on exit: " + state);
switch (state) {
case LOGGED_IN:
return "";
case FORCED_PASSWORD_CHANGE:
return doTemplate(vreq, showPasswordChangeScreen(vreq));
default:
return doTemplate(vreq, showLoginScreen(vreq));
}
} catch (TemplateProcessingException e) {
log.error(e.getMessage(), e);
return null;
} catch (Exception e) {
log.error(e, e);
try {
return doTemplate(vreq, showError(e));
} catch (TemplateProcessingException e1) {
log.error(e1.getMessage(), e1);
return null;
}
}
}
/** Version for Freemarker page */
public TemplateResponseValues showLoginPanel(VitroRequest vreq) {
try {
State state = getCurrentLoginState(vreq);
log.debug("State on exit: " + state);
switch (state) {
// RY Why does this case exist? We don't call this method if a user is logged in.
case LOGGED_IN:
return null;
case FORCED_PASSWORD_CHANGE:
// return doTemplate(vreq, showPasswordChangeScreen(vreq), body, config);
return showPasswordChangeScreen(vreq);
default:
// return doTemplate(vreq, showLoginScreen(vreq), body, config);
return showLoginScreen(vreq);
}
} catch (Exception e) {
log.error(e, e);
return showError(e);
}
}
/**
* User is just starting the login process. Be sure that we have a
* {@link LoginProcessBean} with the correct status. Show them the login
* screen.
*/
private TemplateResponseValues showLoginScreen(VitroRequest vreq)
throws IOException {
LoginProcessBean bean = LoginProcessBean.getBean(vreq);
bean.setState(State.LOGGING_IN);
log.trace("Going to login screen: " + bean);
TemplateResponseValues trv = new TemplateResponseValues(TEMPLATE_LOGIN);
trv.put(BODY_FORM_ACTION, getAuthenticateUrl(vreq));
trv.put(BODY_LOGIN_NAME, bean.getUsername());
String infoMessage = bean.getInfoMessageAndClear();
if (!infoMessage.isEmpty()) {
trv.put(BODY_INFO_MESSAGE, infoMessage);
}
String errorMessage = bean.getErrorMessageAndClear();
if (!errorMessage.isEmpty()) {
trv.put(BODY_ERROR_MESSAGE, errorMessage);
}
return trv;
}
/**
* The user has given the correct password, but now they are required to
* change it (unless they cancel out).
*/
private TemplateResponseValues showPasswordChangeScreen(VitroRequest vreq) {
LoginProcessBean bean = LoginProcessBean.getBean(vreq);
bean.setState(State.FORCED_PASSWORD_CHANGE);
log.trace("Going to password change screen: " + bean);
TemplateResponseValues trv = new TemplateResponseValues(
TEMPLATE_FORCE_PASSWORD_CHANGE);
trv.put(BODY_FORM_ACTION, getAuthenticateUrl(vreq));
trv.put(BODY_CANCEL_URL, getCancelUrl(vreq));
String errorMessage = bean.getErrorMessageAndClear();
if (!errorMessage.isEmpty()) {
trv.put(BODY_ERROR_MESSAGE, errorMessage);
}
return trv;
}
private TemplateResponseValues showError(Exception e) {
TemplateResponseValues trv = new TemplateResponseValues(
TEMPLATE_SERVER_ERROR);
trv.put(BODY_ERROR_MESSAGE, "Internal server error:<br /> " + e);
return trv;
}
/**
* We processed a response, and want to show a template. Version for JSP
* page.
*/
private String doTemplate(VitroRequest vreq, TemplateResponseValues values) throws TemplateProcessingException {
// Set it up like FreeMarkerHttpServlet.doGet() would do.
Map<String, Object> map = new HashMap<String, Object>();
map.putAll(getPageTemplateValues(vreq));
map.putAll(values.getMap());
return processTemplateToString(values.getTemplateName(), map, vreq);
}
/**
* Where are we in the process? Logged in? Not? Somewhere in between?
*/
private State getCurrentLoginState(HttpServletRequest request) {
if (LoginStatusBean.getBean(request).isLoggedIn()) {
return State.LOGGED_IN;
} else {
return LoginProcessBean.getBean(request).getState();
}
}
/** What's the URL for this servlet? */
private String getAuthenticateUrl(HttpServletRequest request) {
String contextPath = request.getContextPath();
String urlParams = "?login=block";
return contextPath + "/authenticate" + urlParams;
}
/** What's the URL for this servlet, with the cancel parameter added? */
private String getCancelUrl(HttpServletRequest request) {
String contextPath = request.getContextPath();
String urlParams = "?login=block&cancel=true";
return contextPath + "/authenticate" + urlParams;
}
}

View file

@ -1,27 +0,0 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.controller.login;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServlet;
/**
* A temporary means of displaying the Login templates within the SiteAdmin
* form.
*
* The constructor insures that the ServletContext is set.
*/
public class LoginTemplateHelperBase extends FreemarkerHttpServlet {
private final ServletContext servletContext;
LoginTemplateHelperBase(HttpServletRequest req) {
this.servletContext = req.getSession().getServletContext();
}
public ServletContext getServletContext() {
return servletContext;
}
}

View file

@ -438,13 +438,17 @@ public class IndividualDaoSDB extends IndividualDaoJena {
final List<String> list = final List<String> list =
new LinkedList<String>(); new LinkedList<String>();
// get all labeled resources from any non-tbox and non-metadata graphs. // get all labeled resources from any non-tbox and non-metadata graphs,
// as well as the unnamed graph (first pattern below)
String query = "SELECT DISTINCT ?ind WHERE { \n" + String query = "SELECT DISTINCT ?ind WHERE { \n" +
" { ?ind <" + RDFS.label.getURI() + "> ?label } " +
" UNION { " +
" GRAPH ?g { ?ind <" + RDFS.label.getURI() + " GRAPH ?g { ?ind <" + RDFS.label.getURI() +
"> ?label } \n" + "> ?label } \n" +
" FILTER (?g != <" + JenaDataSourceSetupBase " FILTER (?g != <" + JenaDataSourceSetupBase
.JENA_APPLICATION_METADATA_MODEL + "> " + .JENA_APPLICATION_METADATA_MODEL + "> " +
" && !regex(str(?g),\"tbox\")) \n " + " && !regex(str(?g),\"tbox\")) \n " +
" } " +
"}"; "}";
Query q = QueryFactory.create(query); Query q = QueryFactory.create(query);

View file

@ -848,14 +848,19 @@ public class IndividualSDB extends IndividualImpl implements Individual {
String getTypes = String getTypes =
"CONSTRUCT{ <" + this.individualURI + "> <" + RDF.type + "CONSTRUCT{ <" + this.individualURI + "> <" + RDF.type +
"> ?types }\n" + "> ?types }\n" +
"WHERE{ GRAPH ?g" "WHERE{ { GRAPH ?g"
+ " { <" + this.individualURI +"> <" +RDF.type+ "> ?types } \n" + " { <" + this.individualURI +"> <" +RDF.type+ "> ?types } \n"
+ WebappDaoFactorySDB.getFilterBlock( + WebappDaoFactorySDB.getFilterBlock(
graphVars, (direct graphVars, (direct
? WebappDaoFactorySDB.SDBDatasetMode ? WebappDaoFactorySDB.SDBDatasetMode
.ASSERTIONS_ONLY .ASSERTIONS_ONLY
: datasetMode)) : datasetMode))
+ "} \n"; + "} \n"
// GRAPH-less pattern to support retrieving inferred types
// from the unnamed base graph, as in Sesame and OWLIM
+ ((datasetMode.equals(WebappDaoFactorySDB.SDBDatasetMode.ASSERTIONS_ONLY))
? "" : "UNION { <" + this.individualURI +"> <" +RDF.type+ "> ?types }" )
+ "} \n";
RDFService service = webappDaoFactory.getRDFService(); RDFService service = webappDaoFactory.getRDFService();
try { try {
tempModel = RDFServiceUtils.parseModel( tempModel = RDFServiceUtils.parseModel(

View file

@ -139,10 +139,8 @@ public class VClassDaoSDB extends VClassDaoJena {
try { try {
String queryText = String queryText =
"SELECT COUNT( DISTINCT ?instance ) WHERE { \n" + "SELECT COUNT( DISTINCT ?instance ) WHERE { \n" +
" GRAPH <urn:x-arq:UnionGraph> { \n" +
" ?class <"+VitroVocabulary.IN_CLASSGROUP+"> <"+vcg.getURI() +"> .\n" + " ?class <"+VitroVocabulary.IN_CLASSGROUP+"> <"+vcg.getURI() +"> .\n" +
" ?instance a ?class . \n" + " ?instance a ?class . \n" +
" } \n" +
"} \n" ; "} \n" ;
Query countQuery = QueryFactory.create(queryText, Syntax.syntaxARQ); Query countQuery = QueryFactory.create(queryText, Syntax.syntaxARQ);

View file

@ -66,16 +66,29 @@ public class IndividualsViaObjectPropetyOptions implements FieldOptions {
Individual subject = wDaoFact.getIndividualDao().getIndividualByURI(subjectUri); Individual subject = wDaoFact.getIndividualDao().getIndividualByURI(subjectUri);
ObjectProperty objProp = wDaoFact.getObjectPropertyDao().getObjectPropertyByURI(predicateUri); ObjectProperty objProp = wDaoFact.getObjectPropertyDao().getObjectPropertyByURI(predicateUri);
List<VClass> vclasses = wDaoFact.getVClassDao().getVClassesForProperty(subject.getVClassURI(), predicateUri); //get all vclasses applicable to the individual subject
List<VClass> subjectVClasses = subject.getVClasses();
//using hashset to prevent duplicates
HashSet<String> vclassesURIs = new HashSet<String>();
//Get the range vclasses applicable for the property and each vclass for the subject
for(VClass subjectVClass: subjectVClasses) {
List<VClass> vclasses = wDaoFact.getVClassDao().getVClassesForProperty(subjectVClass.getURI(), predicateUri);
//add range vclass to hash
if(vclasses != null) {
for(VClass v: vclasses) {
vclassesURIs.add(v.getURI());
}
}
}
if (vclasses == null || vclasses.size() == 0) { if (vclassesURIs.size() == 0) {
return optionsMap; return optionsMap;
} }
List<Individual> individuals = new ArrayList<Individual>(); List<Individual> individuals = new ArrayList<Individual>();
HashSet<String> uriSet = new HashSet<String>(); HashSet<String> uriSet = new HashSet<String>();
for (VClass vclass : vclasses) { for (String vclassURI: vclassesURIs) {
List<Individual> inds = wDaoFact.getIndividualDao().getIndividualsByVClassURI(vclass.getURI(), -1, -1); List<Individual> inds = wDaoFact.getIndividualDao().getIndividualsByVClassURI(vclassURI, -1, -1);
for (Individual ind : inds) { for (Individual ind : inds) {
if (!uriSet.contains(ind.getURI())) { if (!uriSet.contains(ind.getURI())) {
uriSet.add(ind.getURI()); uriSet.add(ind.getURI());
@ -88,7 +101,7 @@ public class IndividualsViaObjectPropetyOptions implements FieldOptions {
individuals = removeIndividualsAlreadyInRange( individuals = removeIndividualsAlreadyInRange(
individuals, stmts, predicateUri, objectUri); individuals, stmts, predicateUri, objectUri);
// Collections.sort(individuals,new compareIndividualsByName()); // Collections.sort(individuals,new compareIndividualsByName());a
for (Individual ind : individuals) { for (Individual ind : individuals) {
String uri = ind.getURI(); String uri = ind.getURI();

View file

@ -39,7 +39,17 @@ public class DateTimeIntervalFormGenerator extends
public EditConfigurationVTwo getEditConfiguration(VitroRequest vreq, public EditConfigurationVTwo getEditConfiguration(VitroRequest vreq,
HttpSession session) { HttpSession session) {
EditConfigurationVTwo conf = new EditConfigurationVTwo(); EditConfigurationVTwo conf = new EditConfigurationVTwo();
this.setupEditConfiguration(conf, vreq, session);
//Prepare
prepare(vreq, conf);
return conf;
}
//Enables refactoring by other generators, as this code can be used to partially setup an
//edit configuration object which can then be extended - prepare can then be called independently
//enabling sparql queries to be evaluated using the final edit configuration object
public void setupEditConfiguration(EditConfigurationVTwo conf, VitroRequest vreq, HttpSession session) {
initBasics(conf, vreq); initBasics(conf, vreq);
initPropertyParameters(vreq, session, conf); initPropertyParameters(vreq, session, conf);
initObjectPropForm(conf, vreq); initObjectPropForm(conf, vreq);
@ -48,11 +58,11 @@ public class DateTimeIntervalFormGenerator extends
conf.setVarNameForSubject("subject"); conf.setVarNameForSubject("subject");
conf.setVarNameForPredicate("toDateTimeInterval"); conf.setVarNameForPredicate("toDateTimeInterval");
conf.setVarNameForObject("intervalNode"); conf.setVarNameForObject(getNodeVar());
conf.setN3Optional(Arrays.asList(n3ForStart, n3ForEnd)); conf.setN3Optional(n3ForStart, n3ForEnd);
conf.addNewResource("intervalNode", DEFAULT_NS_FOR_NEW_RESOURCE); conf.addNewResource(getNodeVar(), DEFAULT_NS_FOR_NEW_RESOURCE);
conf.addNewResource("startNode", DEFAULT_NS_FOR_NEW_RESOURCE); conf.addNewResource("startNode", DEFAULT_NS_FOR_NEW_RESOURCE);
conf.addNewResource("endNode", DEFAULT_NS_FOR_NEW_RESOURCE); conf.addNewResource("endNode", DEFAULT_NS_FOR_NEW_RESOURCE);
@ -61,7 +71,7 @@ public class DateTimeIntervalFormGenerator extends
conf.addSparqlForExistingLiteral( conf.addSparqlForExistingLiteral(
"endField-value", existingEndDateQuery); "endField-value", existingEndDateQuery);
conf.addSparqlForExistingUris( conf.addSparqlForExistingUris(
"intervalNode", existingIntervalNodeQuery); getNodeVar(), existingIntervalNodeQuery);
conf.addSparqlForExistingUris("startNode", existingStartNodeQuery); conf.addSparqlForExistingUris("startNode", existingStartNodeQuery);
conf.addSparqlForExistingUris("endNode", existingEndNodeQuery); conf.addSparqlForExistingUris("endNode", existingEndNodeQuery);
conf.addSparqlForExistingUris( conf.addSparqlForExistingUris(
@ -85,79 +95,87 @@ public class DateTimeIntervalFormGenerator extends
conf.addValidator(new DateTimeIntervalValidationVTwo("startField","endField")); conf.addValidator(new DateTimeIntervalValidationVTwo("startField","endField"));
//Adding additional data, specifically edit mode //Adding additional data, specifically edit mode
addFormSpecificData(conf, vreq); addFormSpecificData(conf, vreq);
//Prepare
prepare(vreq, conf);
return conf;
} }
final static String n3ForStart = final String n3ForStart =
"?subject <" + toDateTimeInterval + "> ?intervalNode . \n" + "?subject <" + getToDateTimeIntervalPredicate() + "> " + getNodeN3Var() + " . \n" +
"?intervalNode a <" + intervalType + "> . \n" + getNodeN3Var() + " a <" + intervalType + "> . \n" +
"?intervalNode <" + intervalToStart + "> ?startNode . \n" + getNodeN3Var() + " <" + intervalToStart + "> ?startNode . \n" +
"?startNode a <" + dateTimeValueType + "> . \n" + "?startNode a <" + dateTimeValueType + "> . \n" +
"?startNode <" + dateTimeValue + "> ?startField-value . \n" + "?startNode <" + dateTimeValue + "> ?startField-value . \n" +
"?startNode <" + dateTimePrecision + "> ?startField-precision . \n"; "?startNode <" + dateTimePrecision + "> ?startField-precision . \n";
final static String n3ForEnd = final String n3ForEnd =
"?subject <" + toDateTimeInterval + "> ?intervalNode . \n" + "?subject <" + getToDateTimeIntervalPredicate() + "> " + getNodeN3Var() + " . \n" +
"?intervalNode a <" + intervalType + "> . \n" + getNodeN3Var() + " a <" + intervalType + "> . \n" +
"?intervalNode <" + intervalToEnd + "> ?endNode . \n" + getNodeN3Var() + " <" + intervalToEnd + "> ?endNode . \n" +
"?endNode a <" + dateTimeValueType + "> . \n" + "?endNode a <" + dateTimeValueType + "> . \n" +
"?endNode <" + dateTimeValue + "> ?endField-value . \n" + "?endNode <" + dateTimeValue + "> ?endField-value . \n" +
"?endNode <" + dateTimePrecision + "> ?endField-precision ."; "?endNode <" + dateTimePrecision + "> ?endField-precision .";
final static String existingStartDateQuery = final String existingStartDateQuery =
"SELECT ?existingDateStart WHERE { \n" + "SELECT ?existingDateStart WHERE { \n" +
"?subject <" + toDateTimeInterval + "> ?existingIntervalNode . \n" + "?subject <" + getToDateTimeIntervalPredicate() + "> ?existingIntervalNode . \n" +
"?intervalNode a <" + intervalType + "> . \n" + getNodeN3Var() + " a <" + intervalType + "> . \n" +
"?intervalNode <" + intervalToStart + "> ?startNode . \n" + getNodeN3Var() + " <" + intervalToStart + "> ?startNode . \n" +
"?startNode a <" + dateTimeValueType + "> . \n" + "?startNode a <" + dateTimeValueType + "> . \n" +
"?startNode <" + dateTimeValue + "> ?existingDateStart }"; "?startNode <" + dateTimeValue + "> ?existingDateStart }";
final static String existingEndDateQuery = final String existingEndDateQuery =
"SELECT ?existingEndDate WHERE { \n" + "SELECT ?existingEndDate WHERE { \n" +
"?subject <" + toDateTimeInterval + "> ?existingIntervalNode . \n" + "?subject <" + getToDateTimeIntervalPredicate() + "> ?existingIntervalNode . \n" +
"?intervalNode a <" + intervalType + "> . \n" + getNodeN3Var() + " a <" + intervalType + "> . \n" +
"?intervalNode <" + intervalToEnd + "> ?endNode . \n" + getNodeN3Var() + " <" + intervalToEnd + "> ?endNode . \n" +
"?endNode a <" + dateTimeValueType + "> . \n " + "?endNode a <" + dateTimeValueType + "> . \n " +
"?endNode <" + dateTimeValue + "> ?existingEndDate . }"; "?endNode <" + dateTimeValue + "> ?existingEndDate . }";
final static String existingIntervalNodeQuery = final String existingIntervalNodeQuery =
"SELECT ?existingIntervalNode WHERE { \n" + "SELECT ?existingIntervalNode WHERE { \n" +
"?subject <" + toDateTimeInterval + "> ?existingIntervalNode . \n" + "?subject <" + getToDateTimeIntervalPredicate() + "> ?existingIntervalNode . \n" +
"?existingIntervalNode a <" + intervalType + "> . }"; "?existingIntervalNode a <" + intervalType + "> . }";
final static String existingStartNodeQuery = final String existingStartNodeQuery =
"SELECT ?existingStartNode WHERE { \n" + "SELECT ?existingStartNode WHERE { \n" +
"?subject <" + toDateTimeInterval + "> ?existingIntervalNode . \n" + "?subject <" + getToDateTimeIntervalPredicate() + "> ?existingIntervalNode . \n" +
"?intervalNode a <" + intervalType + "> . \n" + getNodeN3Var() + " a <" + intervalType + "> . \n" +
"?intervalNode <" + intervalToStart + "> ?existingStartNode . \n" + getNodeN3Var() + " <" + intervalToStart + "> ?existingStartNode . \n" +
"?existingStartNode a <" + dateTimeValueType + "> .} "; "?existingStartNode a <" + dateTimeValueType + "> .} ";
final static String existingEndNodeQuery = final String existingEndNodeQuery =
"SELECT ?existingEndNode WHERE { \n" + "SELECT ?existingEndNode WHERE { \n" +
"?subject <" + toDateTimeInterval + "> ?existingIntervalNode . \n" + "?subject <" + getToDateTimeIntervalPredicate() + "> ?existingIntervalNode . \n" +
"?intervalNode a <" + intervalType + "> . \n" + getNodeN3Var() + " a <" + intervalType + "> . \n" +
"?intervalNode <" + intervalToEnd + "> ?existingEndNode . \n" + getNodeN3Var() + " <" + intervalToEnd + "> ?existingEndNode . \n" +
"?existingEndNode a <" + dateTimeValueType + "> .} "; "?existingEndNode a <" + dateTimeValueType + "> .} ";
final static String existingStartPrecisionQuery = final String existingStartPrecisionQuery =
"SELECT ?existingStartPrecision WHERE { \n" + "SELECT ?existingStartPrecision WHERE { \n" +
"?subject <" + toDateTimeInterval + "> ?existingIntervalNode . \n" + "?subject <" + getToDateTimeIntervalPredicate() + "> ?existingIntervalNode . \n" +
"?intervalNode a <" + intervalType + "> . \n" + getNodeN3Var() + " a <" + intervalType + "> . \n" +
"?intervalNode <" + intervalToStart + "> ?startNode . \n" + getNodeN3Var() + " <" + intervalToStart + "> ?startNode . \n" +
"?startNode a <" + dateTimeValueType + "> . \n" + "?startNode a <" + dateTimeValueType + "> . \n" +
"?startNode <" + dateTimePrecision + "> ?existingStartPrecision . }"; "?startNode <" + dateTimePrecision + "> ?existingStartPrecision . }";
final static String existingEndPrecisionQuery = final String existingEndPrecisionQuery =
"SELECT ?existingEndPrecision WHERE { \n" + "SELECT ?existingEndPrecision WHERE { \n" +
"?subject <" + toDateTimeInterval + "> ?existingIntervalNode . \n" + "?subject <" + getToDateTimeIntervalPredicate() + "> ?existingIntervalNode . \n" +
"?intervalNode a <" + intervalType + "> . \n" + getNodeN3Var() + " a <" + intervalType + "> . \n" +
"?intervalNode <" + intervalToEnd + "> ?endNode . \n" + getNodeN3Var() + " <" + intervalToEnd + "> ?endNode . \n" +
"?endNode a <" + dateTimeValueType + "> . \n" + "?endNode a <" + dateTimeValueType + "> . \n" +
"?endNode <" + dateTimePrecision + "> ?existingEndPrecision . }"; "?endNode <" + dateTimePrecision + "> ?existingEndPrecision . }";
public String getToDateTimeIntervalPredicate() {
return toDateTimeInterval;
}
public String getNodeVar() {
return "intervalNode";
}
public String getNodeN3Var() {
return "?" + getNodeVar();
}
//Adding form specific data such as edit mode //Adding form specific data such as edit mode
public void addFormSpecificData(EditConfigurationVTwo editConfiguration, VitroRequest vreq) { public void addFormSpecificData(EditConfigurationVTwo editConfiguration, VitroRequest vreq) {
HashMap<String, Object> formSpecificData = new HashMap<String, Object>(); HashMap<String, Object> formSpecificData = new HashMap<String, Object>();

View file

@ -27,7 +27,7 @@ public class DateTimeValueFormGenerator extends BaseEditConfigurationGenerator
implements EditConfigurationGenerator { implements EditConfigurationGenerator {
final static String vivoCore = "http://vivoweb.org/ontology/core#"; final static String vivoCore = "http://vivoweb.org/ontology/core#";
final static String toDateTimeValue = vivoCore + "dateTimeValue"; final String toDateTimeValue = vivoCore + "dateTimeValue";
final static String valueType = vivoCore + "DateTimeValue"; final static String valueType = vivoCore + "DateTimeValue";
final static String dateTimeValue = vivoCore + "dateTime"; final static String dateTimeValue = vivoCore + "dateTime";
final static String dateTimePrecision = vivoCore + "dateTimePrecision"; final static String dateTimePrecision = vivoCore + "dateTimePrecision";
@ -41,23 +41,23 @@ public class DateTimeValueFormGenerator extends BaseEditConfigurationGenerator
initPropertyParameters(vreq, session, conf); initPropertyParameters(vreq, session, conf);
initObjectPropForm(conf, vreq); initObjectPropForm(conf, vreq);
conf.setTemplate("dateTimeValueForm.ftl"); conf.setTemplate(this.getTemplate());
conf.setVarNameForSubject("subject"); conf.setVarNameForSubject("subject");
conf.setVarNameForPredicate("toDateTimeValue"); conf.setVarNameForPredicate("toDateTimeValue");
conf.setVarNameForObject("valueNode"); conf.setVarNameForObject("valueNode");
conf.setN3Optional(Arrays.asList(n3ForValue)); conf.setN3Optional(Arrays.asList(getN3ForValue()));
conf.addNewResource("valueNode", DEFAULT_NS_FOR_NEW_RESOURCE); conf.addNewResource("valueNode", DEFAULT_NS_FOR_NEW_RESOURCE);
conf.addSparqlForExistingLiteral( conf.addSparqlForExistingLiteral(
"dateTimeField-value", existingDateTimeValueQuery); "dateTimeField-value", getExistingDateTimeValueQuery());
conf.addSparqlForExistingUris( conf.addSparqlForExistingUris(
"dateTimeField-precision", existingPrecisionQuery); "dateTimeField-precision", getExistingPrecisionQuery());
conf.addSparqlForExistingUris("valueNode", existingNodeQuery); conf.addSparqlForExistingUris("valueNode", getExistingNodeQuery());
FieldVTwo dateTimeField = new FieldVTwo().setName("dateTimeField"); FieldVTwo dateTimeField = new FieldVTwo().setName(this.getDateTimeFieldName());
dateTimeField.setEditElement(new DateTimeWithPrecisionVTwo(dateTimeField, dateTimeField.setEditElement(new DateTimeWithPrecisionVTwo(dateTimeField,
VitroVocabulary.Precision.SECOND.uri(), VitroVocabulary.Precision.SECOND.uri(),
VitroVocabulary.Precision.NONE.uri())); VitroVocabulary.Precision.NONE.uri()));
@ -71,30 +71,57 @@ public class DateTimeValueFormGenerator extends BaseEditConfigurationGenerator
return conf; return conf;
} }
final static String n3ForValue =
"?subject <" + toDateTimeValue + "> ?valueNode . \n" + //Writing these as methods instead of static strings allows the method getToDateTimeValuePredicate
//to be called after the class has been initialized - this is important for subclasses of this generator
//that rely on vreq for predicate
protected String getN3ForValue() {
return "?subject <" + this.getToDateTimeValuePredicate() + "> ?valueNode . \n" +
"?valueNode a <" + valueType + "> . \n" + "?valueNode a <" + valueType + "> . \n" +
"?valueNode <" + dateTimeValue + "> ?dateTimeField-value . \n" + "?valueNode <" + dateTimeValue + "> ?dateTimeField-value . \n" +
"?valueNode <" + dateTimePrecision + "> ?dateTimeField-precision ."; "?valueNode <" + dateTimePrecision + "> ?dateTimeField-precision .";
}
final static String existingDateTimeValueQuery = protected String getExistingDateTimeValueQuery () {
"SELECT ?existingDateTimeValue WHERE { \n" + return "SELECT ?existingDateTimeValue WHERE { \n" +
"?subject <" + toDateTimeValue + "> ?existingValueNode . \n" + "?subject <" + this.getToDateTimeValuePredicate() + "> ?existingValueNode . \n" +
"?existingValueNode a <" + valueType + "> . \n" + "?existingValueNode a <" + valueType + "> . \n" +
"?existingValueNode <" + dateTimeValue + "> ?existingDateTimeValue }"; "?existingValueNode <" + dateTimeValue + "> ?existingDateTimeValue }";
}
final static String existingPrecisionQuery = protected String getExistingPrecisionQuery() {
"SELECT ?existingPrecision WHERE { \n" + return "SELECT ?existingPrecision WHERE { \n" +
"?subject <" + toDateTimeValue + "> ?existingValueNode . \n" + "?subject <" + this.getToDateTimeValuePredicate() + "> ?existingValueNode . \n" +
"?existingValueNode a <" + valueType + "> . \n" + "?existingValueNode a <" + valueType + "> . \n" +
"?existingValueNode <" + dateTimePrecision + "> ?existingPrecision }"; "?existingValueNode <" + dateTimePrecision + "> ?existingPrecision }";
}
final static String existingNodeQuery = protected String getExistingNodeQuery() {
"SELECT ?existingNode WHERE { \n" + return "SELECT ?existingNode WHERE { \n" +
"?subject <" + toDateTimeValue + "> ?existingNode . \n" + "?subject <" + this.getToDateTimeValuePredicate() + "> ?existingNode . \n" +
"?existingNode a <" + valueType + "> }"; "?existingNode a <" + valueType + "> }";
}
public static String getNodeVar() {
return "valueNode";
}
public static String getNodeN3Var() {
return "?" + getNodeVar();
}
//isolating the predicate in this fashion allows this class to be subclassed for other date time value
//properties
protected String getToDateTimeValuePredicate() {
return this.toDateTimeValue;
}
protected String getDateTimeFieldName() {
return "dateTimeField";
}
protected String getTemplate() {
return "dateTimeValueForm.ftl";
}
//Adding form specific data such as edit mode //Adding form specific data such as edit mode
public void addFormSpecificData(EditConfigurationVTwo editConfiguration, VitroRequest vreq) { public void addFormSpecificData(EditConfigurationVTwo editConfiguration, VitroRequest vreq) {
HashMap<String, Object> formSpecificData = new HashMap<String, Object>(); HashMap<String, Object> formSpecificData = new HashMap<String, Object>();

View file

@ -7,6 +7,7 @@ import static edu.cornell.mannlib.vitro.webapp.dao.DisplayVocabulary.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -101,15 +102,23 @@ public class DefaultObjectPropertyFormGenerator implements EditConfigurationGene
} }
protected List<String> getRangeTypes(VitroRequest vreq) { protected List<String> getRangeTypes(VitroRequest vreq) {
Individual subject = EditConfigurationUtils.getSubjectIndividual(vreq); Individual subject = EditConfigurationUtils.getSubjectIndividual(vreq);
String predicateUri = EditConfigurationUtils.getPredicateUri(vreq); String predicateUri = EditConfigurationUtils.getPredicateUri(vreq);
WebappDaoFactory wDaoFact = vreq.getWebappDaoFactory(); WebappDaoFactory wDaoFact = vreq.getWebappDaoFactory();
List<String> types = new ArrayList<String>(); List<String> types = new ArrayList<String>();
List <VClass> vclasses = new ArrayList<VClass>(); //Get all vclasses applicable to subject
vclasses = wDaoFact.getVClassDao().getVClassesForProperty(subject.getVClassURI(),predicateUri); List<VClass> vClasses = subject.getVClasses();
for(VClass v: vclasses) { HashSet<String> typesHash = new HashSet<String>();
types.add(v.getURI()); for(VClass vclass: vClasses) {
} List<VClass> rangeVclasses = wDaoFact.getVClassDao().getVClassesForProperty(vclass.getURI(),predicateUri);
if(rangeVclasses != null) {
for(VClass range: rangeVclasses) {
//a hash will keep a unique list of types and so prevent duplicates
typesHash.add(range.getURI());
}
}
}
types.addAll(typesHash);
return types; return types;
} }

View file

@ -0,0 +1,11 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo;
//For use with classes that explicitly modify configurations through AJAX requests
public interface EditConfigurationAJAXGenerator {
public void modifyEditConfiguration( EditConfigurationVTwo config, VitroRequest vreq ) throws Exception;
}

View file

@ -128,10 +128,11 @@ public class ProcessSparqlDataGetterN3 extends ProcessDataGetterAbstract {
existingLiteralValues.put(this.getVarName("query", counter), existingLiteralValues.put(this.getVarName("query", counter),
new ArrayList<Literal>(Arrays.asList(queryLiteral))); new ArrayList<Literal>(Arrays.asList(queryLiteral)));
//Query model is optional
existingUriValues.put(this.getVarName("queryModel", counter), if(queryModelResource != null && queryModelResource.getURI() != null) {
existingUriValues.put(this.getVarName("queryModel", counter),
new ArrayList<String>(Arrays.asList(queryModelResource.getURI()))); new ArrayList<String>(Arrays.asList(queryModelResource.getURI())));
}
} }
} catch(Exception ex) { } catch(Exception ex) {

View file

@ -0,0 +1,132 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.edit.n3editing.controller;
import static edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationUtils.getPredicateUri;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.hp.hpl.jena.vocabulary.RDFS;
import edu.cornell.mannlib.vitro.webapp.auth.permissions.SimplePermission;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions;
import edu.cornell.mannlib.vitro.webapp.beans.DataProperty;
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
import edu.cornell.mannlib.vitro.webapp.beans.Property;
import edu.cornell.mannlib.vitro.webapp.controller.VitroHttpServlet;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServlet;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMap;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.DirectRedirectResponseValues;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues;
import edu.cornell.mannlib.vitro.webapp.controller.json.GetDataForPage;
import edu.cornell.mannlib.vitro.webapp.controller.json.GetEntitiesByVClass;
import edu.cornell.mannlib.vitro.webapp.controller.json.GetEntitiesByVClassContinuation;
import edu.cornell.mannlib.vitro.webapp.controller.json.GetRenderedSolrIndividualsByVClass;
import edu.cornell.mannlib.vitro.webapp.controller.json.GetSolrIndividualsByVClass;
import edu.cornell.mannlib.vitro.webapp.controller.json.GetSolrIndividualsByVClasses;
import edu.cornell.mannlib.vitro.webapp.controller.json.GetVClassesForVClassGroup;
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationUtils;
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo;
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditSubmissionUtils;
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.MultiValueEditSubmission;
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators.EditConfigurationAJAXGenerator;
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators.EditConfigurationGenerator;
import edu.cornell.mannlib.vitro.webapp.utils.log.LogUtils;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.edit.EditConfigurationTemplateModel;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.edit.MultiValueEditSubmissionTemplateModel;
/**
* This servlet is intended to handle all requests to create a form for use
* by the N3 editing system. It will examine the request parameters, determine
* which form to use, execute a EditConfiguration setup, and evaluate the
* view indicated by the EditConfiguration.
*
* Do not add code to this class to achieve some behavior in a
* form. Try adding the behavior logic to the code that generates the
* EditConfiguration for the form.
*/
public class EditRequestAJAXController extends VitroHttpServlet {
private static final long serialVersionUID = 1L;
public static Log log = LogFactory.getLog(EditRequestDispatchController.class);
protected Actions requiredActions(VitroRequest vreq) {
return SimplePermission.DO_FRONT_END_EDITING.ACTIONS;
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
log.debug(LogUtils.formatRequestProperties(log, "debug", req));
VitroRequest vreq = new VitroRequest(req);
try {
//Get edit configuration object based on editk key in request
EditConfigurationVTwo config = getEditConfiguration(vreq);
//Get the generator name also from the request parameter
String generatorName = vreq.getParameter("generator");
String javaGeneratorName = "edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators." + generatorName;
//TODO: Add this method to generators, but for now constructing a new class of generator specifically for AJAX requests
EditConfigurationAJAXGenerator generator = getAJAXGenerator(javaGeneratorName, vreq, vreq.getSession());
//run the modification
generator.modifyEditConfiguration(config, vreq);
} catch(Exception ex) {
log.error("An error occurred in retrieving configuration and/or generator ", ex);
}
}
protected EditConfigurationVTwo getEditConfiguration(VitroRequest vreq) {
EditConfigurationVTwo config = EditConfigurationVTwo.getConfigFromSession(vreq.getSession(), vreq);
return config;
}
private EditConfigurationAJAXGenerator getAJAXGenerator(
String editConfGeneratorName, VitroRequest vreq, HttpSession session) throws Exception {
EditConfigurationAJAXGenerator EditConfigurationVTwoGenerator = null;
Object object = null;
try {
Class classDefinition = Class.forName(editConfGeneratorName);
object = classDefinition.newInstance();
EditConfigurationVTwoGenerator = (EditConfigurationAJAXGenerator) object;
} catch (InstantiationException e) {
System.out.println(e);
} catch (IllegalAccessException e) {
System.out.println(e);
} catch (ClassNotFoundException e) {
System.out.println(e);
}
if(EditConfigurationVTwoGenerator == null){
throw new Error("Could not find EditConfigurationVTwoGenerator " + editConfGeneratorName);
} else {
return EditConfigurationVTwoGenerator;
}
}
}

View file

@ -155,12 +155,25 @@ public class EditRequestDispatchController extends FreemarkerHttpServlet {
private EditConfigurationVTwo setupEditConfiguration(String editConfGeneratorName, private EditConfigurationVTwo setupEditConfiguration(String editConfGeneratorName,
VitroRequest vreq) throws Exception { VitroRequest vreq) throws Exception {
HttpSession session = vreq.getSession(); HttpSession session = vreq.getSession();
EditConfigurationVTwo editConfig = //Originally, this code called makeEditConfiguration before checking for/setting the edit key
makeEditConfigurationVTwo( editConfGeneratorName, vreq, session); //which meant that in the case of page reload on an error, you would recreate an edit configuration
//using the generator
//Given recent updates enabling modification of edit configuration dynamically through AJAX,
//we will first check whether the edit key exists and if there is already an edit configuration
//in the session - and then will utilize the edit configuration that already exists
//edit key is set here, NOT in the generator class
EditConfigurationVTwo editConfig = null;
EditConfigurationVTwo existingConfig = EditConfigurationVTwo.getConfigFromSession(session, vreq);
if(existingConfig != null) {
editConfig = existingConfig;
} else {
editConfig =
makeEditConfigurationVTwo( editConfGeneratorName, vreq, session);
}
//edit key is set here, NOT in the generator class
String editKey = EditConfigurationUtils.getEditKey(vreq); String editKey = EditConfigurationUtils.getEditKey(vreq);
editConfig.setEditKey(editKey); editConfig.setEditKey(editKey);
//put edit configuration in session so it can be accessed on form submit. //put edit configuration in session so it can be accessed on form submit.
EditConfigurationVTwo.putConfigInSession(editConfig, session); EditConfigurationVTwo.putConfigInSession(editConfig, session);

View file

@ -35,7 +35,7 @@ public class FileStorageSetup implements ServletContextListener {
* {@link ConfigurationProperties} for the vivo home directory. The file * {@link ConfigurationProperties} for the vivo home directory. The file
* storage base directory is in a subdirectory below this one. * storage base directory is in a subdirectory below this one.
*/ */
public static final String PROPERTY_VITRO_HOME_DIR = "vitro.home.directory"; public static final String PROPERTY_VITRO_HOME_DIR = "vitro.home";
public static final String FILE_STORAGE_SUBDIRECTORY = "uploads"; public static final String FILE_STORAGE_SUBDIRECTORY = "uploads";
/** /**

View file

@ -94,6 +94,10 @@ public class FileServingServlet extends VitroHttpServlet {
String actualFilename = findAndValidateFilename(fileInfo, path); String actualFilename = findAndValidateFilename(fileInfo, path);
in = openImageInputStream(fileInfo, actualFilename); in = openImageInputStream(fileInfo, actualFilename);
} catch (FileServingException e) {
log.info("Failed to serve the file at '" + path + "' -- " + e.getMessage());
in = openMissingLinkImage(request);
mimeType = "image/png";
} catch (Exception e) { } catch (Exception e) {
log.warn("Failed to serve the file at '" + path + "' -- " + e.getMessage()); log.warn("Failed to serve the file at '" + path + "' -- " + e.getMessage());
in = openMissingLinkImage(request); in = openMissingLinkImage(request);

View file

@ -21,6 +21,8 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import edu.cornell.mannlib.vitro.webapp.beans.ApplicationBean; import edu.cornell.mannlib.vitro.webapp.beans.ApplicationBean;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus; import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
import freemarker.cache.WebappTemplateLoader; import freemarker.cache.WebappTemplateLoader;
import freemarker.template.Configuration; import freemarker.template.Configuration;
@ -67,9 +69,10 @@ public class StartupStatusDisplayFilter implements Filter {
statusAlreadyDisplayed = true; statusAlreadyDisplayed = true;
} }
private void displayStartupStatus(ServletRequest req, ServletResponse resp) throws IOException, private void displayStartupStatus(ServletRequest req, ServletResponse resp)
ServletException { throws IOException, ServletException {
HttpServletResponse hResp = (HttpServletResponse) resp; HttpServletResponse hresp = (HttpServletResponse) resp;
HttpServletRequest hreq = (HttpServletRequest) req;
try { try {
Map<String, Object> bodyMap = new HashMap<String, Object>(); Map<String, Object> bodyMap = new HashMap<String, Object>();
@ -78,25 +81,24 @@ public class StartupStatusDisplayFilter implements Filter {
bodyMap.put("contextPath", getContextPath()); bodyMap.put("contextPath", getContextPath());
bodyMap.put("applicationName", getApplicationName()); bodyMap.put("applicationName", getApplicationName());
HttpServletRequest httpreq = (HttpServletRequest) req; String url = "";
String url = "";
String path = httpreq.getRequestURI(); String path = hreq.getRequestURI();
if( path != null ){ if (path != null) {
url = path; url = path;
} }
String query = httpreq.getQueryString(); String query = hreq.getQueryString();
if( !StringUtils.isEmpty( query )){ if (!StringUtils.isEmpty(query)) {
url = url + "?" + query; url = url + "?" + query;
} }
bodyMap.put("url", url ); bodyMap.put("url", url);
hResp.setContentType("text/html;charset=UTF-8"); hresp.setContentType("text/html;charset=UTF-8");
hResp.setStatus(SC_INTERNAL_SERVER_ERROR); hresp.setStatus(SC_INTERNAL_SERVER_ERROR);
Template tpl = loadFreemarkerTemplate(); Template tpl = loadFreemarkerTemplate();
tpl.process(bodyMap, hResp.getWriter()); tpl.process(bodyMap, hresp.getWriter());
} catch (TemplateException e) { } catch (TemplateException e) {
throw new ServletException("Problem with Freemarker Template", e); throw new ServletException("Problem with Freemarker Template", e);
} }
@ -114,7 +116,9 @@ public class StartupStatusDisplayFilter implements Filter {
private Object getApplicationName() { private Object getApplicationName() {
String name = ""; String name = "";
try { try {
ApplicationBean app = ApplicationBean.getAppBean(ctx); WebappDaoFactory wadf = (WebappDaoFactory) ctx
.getAttribute("webappDaoFactory");
ApplicationBean app = wadf.getApplicationDao().getApplicationBean();
name = app.getApplicationName(); name = app.getApplicationName();
} catch (Exception e) { } catch (Exception e) {
// deal with problems below // deal with problems below

View file

@ -38,7 +38,6 @@ import edu.cornell.mannlib.vitro.webapp.auth.identifier.RequestIdentifiers;
import edu.cornell.mannlib.vitro.webapp.auth.permissions.SimplePermission; import edu.cornell.mannlib.vitro.webapp.auth.permissions.SimplePermission;
import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper; import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ServletPolicyList; import edu.cornell.mannlib.vitro.webapp.auth.policy.ServletPolicyList;
import edu.cornell.mannlib.vitro.webapp.beans.ApplicationBean;
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties; import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
import edu.cornell.mannlib.vitro.webapp.controller.VitroHttpServlet; import edu.cornell.mannlib.vitro.webapp.controller.VitroHttpServlet;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
@ -82,19 +81,10 @@ public class VitroRequestPrep implements Filter {
}; };
private ServletContext _context; private ServletContext _context;
private ApplicationBean _appbean;
@Override @Override
public void init(FilterConfig filterConfig) throws ServletException { public void init(FilterConfig filterConfig) throws ServletException {
_context = filterConfig.getServletContext(); _context = filterConfig.getServletContext();
Object o = _context.getAttribute("applicationBean");
if (o instanceof ApplicationBean) {
_appbean = (ApplicationBean) o;
} else {
_appbean = new ApplicationBean();
}
log.debug("VitroRequestPrep: AppBean theme " + _appbean.getThemeDir());
} }
@Override @Override
@ -132,9 +122,6 @@ public class VitroRequestPrep implements Filter {
VitroRequest vreq = new VitroRequest(req); VitroRequest vreq = new VitroRequest(req);
//-- setup appBean --//
vreq.setAppBean(_appbean);
//-- setup DAO factory --// //-- setup DAO factory --//
WebappDaoFactory wdf = getWebappDaoFactory(vreq); WebappDaoFactory wdf = getWebappDaoFactory(vreq);
//TODO: get accept-language from request and set as preferred languages //TODO: get accept-language from request and set as preferred languages

View file

@ -0,0 +1,231 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.i18n;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.ResourceBundle.Control;
import java.util.concurrent.atomic.AtomicReference;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
/**
* Provides access to a bundle of text strings, based on the name of the bundle,
* the Locale of the requesting browser, and the current theme directory.
*
* If the bundle name is not specified, the default name of "all" is used.
*
* If a requested bundle is not found, no error is thrown. Instead, an empty
* bundle is returned that produces error message strings when asked for text.
*/
public class I18n {
private static final Log log = LogFactory.getLog(I18n.class);
public static final String DEFAULT_BUNDLE_NAME = "all";
private static final String PROPERTY_DEVELOPER_DEFEAT_CACHE = "developer.defeatI18nCache";
/**
* This is where the work gets done. Not declared final, so it can be
* modified in unit tests.
*/
private static I18n instance = new I18n();
// ----------------------------------------------------------------------
// Static methods
// ----------------------------------------------------------------------
/**
* A convenience method to get a bundle and format the text.
*/
public static String text(String bundleName, HttpServletRequest req,
String key, Object... parameters) {
return bundle(bundleName, req).text(key, parameters);
}
/**
* A convenience method to get the default bundle and format the text.
*/
public static String text(HttpServletRequest req, String key,
Object... parameters) {
return bundle(req).text(key, parameters);
}
/**
* Get a I18nBundle by this name.
*/
public static I18nBundle bundle(String bundleName, HttpServletRequest req) {
return instance.getBundle(bundleName, req);
}
/**
* Get the default I18nBundle.
*/
public static I18nBundle bundle(HttpServletRequest req) {
return instance.getBundle(DEFAULT_BUNDLE_NAME, req);
}
// ----------------------------------------------------------------------
// The instance
// ----------------------------------------------------------------------
/** Holds the current theme directory, as far as we know. */
private AtomicReference<String> themeDirectory = new AtomicReference<String>(
"");
/**
* Get an I18nBundle by this name. The request provides the preferred
* Locale, the application directory, the theme directory and the
* development mode flag.
*
* If the request indicates that the system is in development mode, then the
* cache is cleared on each request.
*
* If the theme directory has changed, the cache is cleared.
*/
private I18nBundle getBundle(String bundleName, HttpServletRequest req) {
log.debug("Getting bundle '" + bundleName + "'");
try {
checkDevelopmentMode(req);
checkForChangeInThemeDirectory(req);
String dir = themeDirectory.get();
ServletContext ctx = req.getSession().getServletContext();
ResourceBundle.Control control = getControl(ctx, dir);
ResourceBundle rb = ResourceBundle.getBundle(bundleName,
req.getLocale(), control);
return new I18nBundle(bundleName, rb);
} catch (MissingResourceException e) {
log.warn("Didn't find text bundle '" + bundleName + "'");
return I18nBundle.emptyBundle(bundleName);
} catch (Exception e) {
log.error("Failed to create text bundle '" + bundleName + "'", e);
return I18nBundle.emptyBundle(bundleName);
}
}
/**
* If we are in development mode, clear the cache on each request.
*/
private void checkDevelopmentMode(HttpServletRequest req) {
ConfigurationProperties bean = ConfigurationProperties.getBean(req);
String flag = bean
.getProperty(PROPERTY_DEVELOPER_DEFEAT_CACHE, "false");
if (Boolean.valueOf(flag.trim())) {
log.debug("In development mode - clearing the cache.");
ResourceBundle.clearCache();
}
}
/**
* If the theme directory has changed from before, clear the cache of all
* ResourceBundles.
*/
private void checkForChangeInThemeDirectory(HttpServletRequest req) {
String currentDir = new VitroRequest(req).getAppBean().getThemeDir();
String previousDir = themeDirectory.getAndSet(currentDir);
if (!currentDir.equals(previousDir)) {
log.debug("Theme directory changed from '" + previousDir + "' to '"
+ currentDir + "' - clearing the cache.");
ResourceBundle.clearCache();
}
}
/**
* Override this method in the unit tests, to return a more testable Control
* instance.
*/
protected Control getControl(ServletContext ctx, String dir) {
return new ThemeBasedControl(ctx, dir);
}
// ----------------------------------------------------------------------
// Control classes for instantiating ResourceBundles
// ----------------------------------------------------------------------
/**
* Instead of looking in the classpath, look in the theme i18n directory and
* the application i18n directory.
*/
private static class ThemeBasedControl extends ResourceBundle.Control {
private static final String BUNDLE_DIRECTORY = "i18n/";
private final ServletContext ctx;
private final String themeDirectory;
public ThemeBasedControl(ServletContext ctx, String themeDirectory) {
this.ctx = ctx;
this.themeDirectory = themeDirectory;
}
/**
* Don't look for classes to satisfy the request, just property files.
*/
@Override
public List<String> getFormats(String baseName) {
return FORMAT_PROPERTIES;
}
/**
* Don't look in the class path, look in the current servlet context, in
* the bundle directory under the theme directory and in the bundle
* directory under the application directory.
*/
@Override
public ResourceBundle newBundle(String baseName, Locale locale,
String format, ClassLoader loader, boolean reload)
throws IllegalAccessException, InstantiationException,
IOException {
checkArguments(baseName, locale, format);
log.debug("Creating bundle for '" + baseName + "', " + locale
+ ", '" + format + "', " + reload);
String bundleName = toBundleName(baseName, locale);
if (bundleName == null) {
throw new NullPointerException("bundleName may not be null.");
}
String themeI18nPath = "/" + themeDirectory + BUNDLE_DIRECTORY;
String appI18nPath = "/" + BUNDLE_DIRECTORY;
log.debug("Paths are '" + themeI18nPath + "' and '" + appI18nPath
+ "'");
return VitroResourceBundle.getBundle(bundleName, ctx, appI18nPath,
themeI18nPath, this);
}
/**
* The documentation for ResourceBundle.Control.newBundle() says I
* should throw these exceptions.
*/
private void checkArguments(String baseName, Locale locale,
String format) {
if (baseName == null) {
throw new NullPointerException("baseName may not be null.");
}
if (locale == null) {
throw new NullPointerException("locale may not be null.");
}
if (format == null) {
throw new NullPointerException("format may not be null.");
}
if (!FORMAT_DEFAULT.contains(format)) {
throw new IllegalArgumentException(
"format must be one of these: " + FORMAT_DEFAULT);
}
}
}
}

View file

@ -0,0 +1,102 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.i18n;
import java.text.MessageFormat;
import java.util.Collections;
import java.util.Enumeration;
import java.util.ResourceBundle;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* A wrapper for a ResourceBundle that will not throw an exception, no matter
* what string you request.
*
* If the ResourceBundle was not found, or if it doesn't contain the requested
* key, an error message string is returned, to help the developer diagnose the
* problem.
*/
public class I18nBundle {
private static final Log log = LogFactory.getLog(I18nBundle.class);
private static final String MESSAGE_BUNDLE_NOT_FOUND = "Text bundle ''{0}'' not found.";
private static final String MESSAGE_KEY_NOT_FOUND = "Text bundle ''{0}'' has no text for ''{1}''";
public static I18nBundle emptyBundle(String bundleName) {
return new I18nBundle(bundleName);
}
private final String bundleName;
private final ResourceBundle resources;
private final String notFoundMessage;
private I18nBundle(String bundleName) {
this(bundleName, new EmptyResourceBundle(), MESSAGE_BUNDLE_NOT_FOUND);
}
public I18nBundle(String bundleName, ResourceBundle resources) {
this(bundleName, resources, MESSAGE_KEY_NOT_FOUND);
}
private I18nBundle(String bundleName, ResourceBundle resources, String notFoundMessage) {
if (bundleName == null) {
throw new IllegalArgumentException("bundleName may not be null");
}
if (bundleName.isEmpty()) {
throw new IllegalArgumentException("bundleName may not be empty");
}
if (resources == null) {
throw new NullPointerException("resources may not be null.");
}if (notFoundMessage == null) {
throw new NullPointerException("notFoundMessage may not be null.");
}
this.bundleName = bundleName;
this.resources = resources;
this.notFoundMessage = notFoundMessage;
}
public String text(String key, Object... parameters) {
log.debug("Asking for '" + key + "' from bundle '" + bundleName + "'");
String textString;
if (resources.containsKey(key)) {
textString = resources.getString(key);
return formatString(textString, parameters);
} else {
String message = MessageFormat.format(notFoundMessage, bundleName,
key);
log.warn(message);
return "ERROR: " + message;
}
}
private static String formatString(String textString, Object... parameters) {
if (parameters.length == 0) {
return textString;
} else {
return MessageFormat.format(textString, parameters);
}
}
/**
* A resource bundle that contains no strings.
*/
public static class EmptyResourceBundle extends ResourceBundle {
@Override
public Enumeration<String> getKeys() {
return Collections.enumeration(Collections.<String> emptySet());
}
@Override
protected Object handleGetObject(String key) {
if (key == null) {
throw new NullPointerException("key may not be null.");
}
return null;
}
}
}

View file

@ -0,0 +1,211 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.i18n;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.text.MessageFormat;
import java.util.Enumeration;
import java.util.Properties;
import java.util.ResourceBundle;
import javax.servlet.ServletContext;
import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Works like a PropertyResourceBundle with two exceptions:
*
* It looks for the file in both the i18n directory of the theme and in the i18n
* directory of the application. Properties found in the theme override those
* found in the application.
*
* It allows a property to take its contents from a file. File paths are
* relative to the i18n directory. Again, a file in the theme will override one
* in the application.
*
* If a property has a value (after overriding) of "@@file <filepath>", the
* bundle looks for the file relative to the i18n directory of the theme, then
* relative to the i18n directory of the application. If the file is not found
* in either location, a warning is written to the log and the property will
* contain an error message for displayed.
*
* Note that the filename is not manipulated for Locale, so the author of the
* properties files must do it explicitly. For example:
*
* In all.properties: account_email_html = @@file accountEmail.html
*
* In all_es.properties: account_email_html = @@file accountEmail_es.html
*/
public class VitroResourceBundle extends ResourceBundle {
private static final Log log = LogFactory.getLog(VitroResourceBundle.class);
private static final String FILE_FLAG = "@@file ";
private static final String MESSAGE_FILE_NOT_FOUND = "File {1} not found for property {0}.";
// ----------------------------------------------------------------------
// Factory method
// ----------------------------------------------------------------------
public static VitroResourceBundle getBundle(String bundleName,
ServletContext ctx, String appI18nPath, String themeI18nPath,
Control control) {
try {
return new VitroResourceBundle(bundleName, ctx, appI18nPath,
themeI18nPath, control);
} catch (FileNotFoundException e) {
log.debug(e);
return null;
} catch (Exception e) {
log.warn(e, e);
return null;
}
}
// ----------------------------------------------------------------------
// The instance
// ----------------------------------------------------------------------
private final String bundleName;
private final ServletContext ctx;
private final String appI18nPath;
private final String themeI18nPath;
private final Control control;
private final Properties defaults;
private final Properties properties;
private VitroResourceBundle(String bundleName, ServletContext ctx,
String appI18nPath, String themeI18nPath, Control control)
throws IOException {
this.bundleName = bundleName;
this.ctx = ctx;
this.appI18nPath = appI18nPath;
this.themeI18nPath = themeI18nPath;
this.control = control;
this.defaults = new Properties();
this.properties = new Properties(this.defaults);
loadProperties();
loadReferencedFiles();
}
private void loadProperties() throws IOException {
String resourceName = control.toResourceName(bundleName, "properties");
String defaultsPath = joinPath(appI18nPath, resourceName);
String propertiesPath = joinPath(themeI18nPath, resourceName);
File defaultsFile = locateFile(defaultsPath);
File propertiesFile = locateFile(propertiesPath);
if ((defaultsFile == null) && (propertiesFile == null)) {
throw new FileNotFoundException("Property file not found at '"
+ defaultsPath + "' or '" + propertiesPath + "'");
}
if (defaultsFile != null) {
log.debug("Loading bundle '" + bundleName + "' defaults from '"
+ defaultsPath + "'");
FileInputStream stream = new FileInputStream(defaultsFile);
Reader reader = new InputStreamReader(stream, "UTF-8");
try {
this.defaults.load(reader);
} finally {
reader.close();
}
}
if (propertiesFile != null) {
log.debug("Loading bundle '" + bundleName + "' overrides from '"
+ propertiesPath + "'");
FileInputStream stream = new FileInputStream(propertiesFile);
Reader reader = new InputStreamReader(stream, "UTF-8");
try {
this.properties.load(reader);
} finally {
reader.close();
}
}
}
private void loadReferencedFiles() throws IOException {
for (String key : this.properties.stringPropertyNames()) {
String value = this.properties.getProperty(key);
if (value.startsWith(FILE_FLAG)) {
String filepath = value.substring(FILE_FLAG.length()).trim();
loadReferencedFile(key, filepath);
}
}
}
private void loadReferencedFile(String key, String filepath)
throws IOException {
String appFilePath = joinPath(appI18nPath, filepath);
String themeFilePath = joinPath(themeI18nPath, filepath);
File appFile = locateFile(appFilePath);
File themeFile = locateFile(themeFilePath);
if (themeFile != null) {
this.properties.setProperty(key,
FileUtils.readFileToString(themeFile, "UTF-8"));
} else if (appFile != null) {
this.properties.setProperty(key,
FileUtils.readFileToString(appFile, "UTF-8"));
} else {
String message = MessageFormat.format(MESSAGE_FILE_NOT_FOUND, key,
themeFilePath, appFilePath);
this.properties.setProperty(key, message);
log.warn(message);
}
}
private String joinPath(String root, String twig) {
if ((root.charAt(root.length() - 1) == File.separatorChar)
|| (twig.charAt(0) == File.separatorChar)) {
return root + twig;
} else {
return root + File.separatorChar + twig;
}
}
private File locateFile(String path) {
String realPath = ctx.getRealPath(path);
if (realPath == null) {
log.debug("No real path for '" + path + "'");
return null;
}
File f = new File(realPath);
if (!f.isFile()) {
log.debug("No file at '" + realPath + "'");
return null;
}
if (!f.canRead()) {
log.error("Can't read the file at '" + realPath + "'");
return null;
}
log.debug("Located file '" + path + "' at '" + realPath + "'");
return f;
}
@SuppressWarnings("unchecked")
@Override
public Enumeration<String> getKeys() {
return (Enumeration<String>) this.properties.propertyNames();
}
@Override
protected Object handleGetObject(String key) {
String value = this.properties.getProperty(key);
if (value == null) {
log.debug(bundleName + " has no value for '" + key + "'");
}
return value;
}
}

View file

@ -0,0 +1,40 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.i18n.freemarker;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.i18n.I18nBundle;
import freemarker.template.TemplateHashModel;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;
/**
* For Freemarker, this acts like a bundle of text strings. It is simply a
* wrapper around an I18nBundle.
*/
public class I18nBundleTemplateModel implements TemplateHashModel {
private static final Log log = LogFactory
.getLog(I18nBundleTemplateModel.class);
private final String bundleName;
private final I18nBundle textBundle;
public I18nBundleTemplateModel(String bundleName, I18nBundle textBundle) {
this.bundleName = bundleName;
this.textBundle = textBundle;
}
@Override
public TemplateModel get(String key) throws TemplateModelException {
return new I18nStringTemplateModel(bundleName, key,
textBundle.text(key));
}
@Override
public boolean isEmpty() throws TemplateModelException {
return false;
}
}

View file

@ -0,0 +1,50 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.i18n.freemarker;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.i18n.I18n;
import edu.cornell.mannlib.vitro.webapp.i18n.I18nBundle;
import freemarker.core.Environment;
import freemarker.template.TemplateMethodModel;
import freemarker.template.TemplateModelException;
/**
* This Freemarker method will produce a bundle of text strings. It is simply a
* wrapper around I18n that produces a wrapped I18nBundle.
*
* If the bundle name is not provided, the default bundle is assumed.
*/
public class I18nMethodModel implements TemplateMethodModel {
private static final Log log = LogFactory.getLog(I18nMethodModel.class);
@SuppressWarnings("rawtypes")
@Override
public Object exec(List args) throws TemplateModelException {
if (args.size() > 1) {
throw new TemplateModelException("Too many arguments: "
+ "displayText method only requires a bundle name.");
}
Object arg = args.isEmpty() ? I18n.DEFAULT_BUNDLE_NAME : args.get(0);
if (!(arg instanceof String)) {
throw new IllegalArgumentException(
"Arguments to a TemplateMethodModel are supposed to be Strings!");
}
log.debug("Asking for this bundle: " + arg);
String bundleName = (String) arg;
Environment env = Environment.getCurrentEnvironment();
HttpServletRequest request = (HttpServletRequest) env
.getCustomAttribute("request");
I18nBundle tb = I18n.bundle(bundleName, request);
return new I18nBundleTemplateModel(bundleName, tb);
}
}

View file

@ -0,0 +1,79 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.i18n.freemarker;
import java.text.MessageFormat;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import freemarker.template.TemplateMethodModelEx;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;
import freemarker.template.TemplateScalarModel;
import freemarker.template.utility.DeepUnwrap;
/**
* A Freemarker representation of a text string. Because it implements
* TemplateScalarModel, you can use it as a string value. And because it
* implements TemplateMethodModel, you can pass arguments to it for formatting.
*
* So if the string is "His name is {0}!", then these references could be used:
*
* ${string} ==> "His name is {0}!"
*
* ${string("Bozo")} ==> "His name is Bozo!"
*
* Note that the format of the message is determined by java.text.MessageFormat,
* so argument indices start at 0 and you can escape a substring by wrapping it
* in apostrophes.
*/
public class I18nStringTemplateModel implements TemplateMethodModelEx,
TemplateScalarModel {
private static final Log log = LogFactory
.getLog(I18nStringTemplateModel.class);
private final String bundleName;
private final String key;
private final String textString;
public I18nStringTemplateModel(String bundleName, String key,
String textString) {
this.bundleName = bundleName;
this.key = key;
this.textString = textString;
}
@Override
public String getAsString() throws TemplateModelException {
return textString;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public Object exec(List args) throws TemplateModelException {
log.debug("Formatting string '" + key + "' from bundle '" + bundleName
+ "' with these arguments: " + args);
if (args.isEmpty()) {
return textString;
} else {
Object[] unwrappedArgs = new Object[args.size()];
for (int i = 0; i < args.size(); i++) {
unwrappedArgs[i] = DeepUnwrap.unwrap((TemplateModel) args
.get(i));
}
try {
return MessageFormat.format(textString, unwrappedArgs);
} catch (Exception e) {
String message = "Can't format '" + key + "' from bundle '"
+ bundleName + "', wrong argument types: " + args
+ " for message format'" + textString + "'";
log.warn(message);
return message;
}
}
}
}

View file

@ -0,0 +1,100 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.i18n.selection;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.LocaleUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.beans.DisplayMessage;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
/**
* Call this at /selectLocale&selection=[locale_string]
*
* For example: /selectLocale&selection=en_US or /selectLocale&selection=es
*
* Write an error to the log (and to DisplayMessage) if the selection is not
* syntactically valid.
*
* Write a warning to the log if the selection code is not one of the selectable
* Locales from runtime.properties, or if the selection code is not recognized
* by the system.
*
* Set the new Locale in the Session using SelectedLocale and return to the
* referrer.
*/
public class LocaleSelectionController extends HttpServlet {
private static final Log log = LogFactory
.getLog(LocaleSelectionController.class);
public static final String PARAMETER_SELECTION = "selection";
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String referrer = req.getHeader("referer");
String selectedLocale = req.getParameter(PARAMETER_SELECTION);
try {
processSelectedLocale(req, selectedLocale);
} catch (Exception e) {
log.error("Failed to process the user's Locale selection", e);
}
if (StringUtils.isEmpty(referrer)) {
resp.sendRedirect(UrlBuilder.getHomeUrl());
} else {
resp.sendRedirect(referrer);
}
}
private void processSelectedLocale(HttpServletRequest req,
String selectedLocale) {
if (StringUtils.isBlank(selectedLocale)) {
log.debug("No '" + PARAMETER_SELECTION + "' parameter");
return;
}
Locale locale = null;
try {
locale = LocaleUtils.toLocale(selectedLocale.trim());
log.debug("Locale selection is " + locale);
} catch (IllegalArgumentException e) {
log.error("Failed to convert the selection to a Locale", e);
DisplayMessage.setMessage(req,
"There was a problem in the system. "
+ "Your language choice was rejected.");
return;
}
List<Locale> selectables = SelectedLocale.getSelectableLocales(req);
if (!selectables.contains(locale)) {
log.warn("User selected a locale '" + locale
+ "' that was not in the list: " + selectables);
} else if (!LocaleUtils.isAvailableLocale(locale)) {
log.warn("User selected an unrecognized locale: '" + locale + "'");
}
SelectedLocale.setSelectedLocale(req, locale);
log.debug("Setting selected locale to " + locale);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req, resp);
}
}

View file

@ -0,0 +1,95 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.i18n.selection;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
import edu.cornell.mannlib.vitro.webapp.utils.dataGetter.DataGetter;
/**
* Get the data for the selectable Locales, so the Freemarker template can
* create a row of flag images that will select the desired locale.
*
* If there are no selectable Locales in runtime.properties, we return an empty
* map. (selectLocale?? will return false)
*
* If the Locale has been forced by runtime.properties, we do the same.
*
* If there are selectable Locales, the returned map will contain a structure
* like this:
*
* <pre>
* {selectLocale={
* selectLocaleUrl = [the URL for the form action to select a Locale]
* locales={ [a list of maps]
* { [a map for each Locale]
* code = [the code for the Locale, e.g. "en_US"]
* label = [the alt text for the Locale, e.g. "Spanish (Spain)"]
* imageUrl = [the URL of the image that represents the Locale]
* }
* }
* }
* }
* </pre>
*/
public class LocaleSelectionDataGetter implements DataGetter {
private static final Log log = LogFactory
.getLog(LocaleSelectionDataGetter.class);
private final VitroRequest vreq;
public LocaleSelectionDataGetter(VitroRequest vreq) {
this.vreq = vreq;
}
@Override
public Map<String, Object> getData(Map<String, Object> valueMap) {
List<Locale> selectables = SelectedLocale.getSelectableLocales(vreq);
if (selectables.isEmpty()) {
return Collections.emptyMap();
}
Map<String, Object> result = new HashMap<String, Object>();
result.put("selectLocaleUrl", UrlBuilder.getUrl("/selectLocale"));
result.put("locales", buildLocalesList(selectables));
Map<String, Object> bodyMap = new HashMap<String, Object>();
bodyMap.put("selectLocale", result);
log.debug("Sending these values: " + bodyMap);
return bodyMap;
}
private List<Map<String, Object>> buildLocalesList(List<Locale> selectables) {
Locale currentLocale = SelectedLocale.getCurrentLocale(vreq);
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
for (Locale locale : selectables) {
try {
list.add(buildLocaleMap(locale, currentLocale));
} catch (FileNotFoundException e) {
log.warn("Can't show the Locale selector for '" + locale
+ "': " + e);
}
}
return list;
}
private Map<String, Object> buildLocaleMap(Locale locale,
Locale currentLocale) throws FileNotFoundException {
Map<String, Object> map = new HashMap<String, Object>();
map.put("code", locale.toString());
map.put("label", locale.getDisplayName(currentLocale));
map.put("imageUrl", LocaleSelectorUtilities.getImageUrl(vreq, locale));
return map;
}
}

View file

@ -0,0 +1,114 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.i18n.selection;
import java.io.IOException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.apache.commons.collections.EnumerationUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Check for a Locale in the ServletContext or the Session that should override
* the Locale in the ServletRequest.
*
* If there is such a Locale, wrap the ServletRequest so it behaves as if that
* is the preferred Locale.
*
* Otherwise, just process the request as usual.
*/
public class LocaleSelectionFilter implements Filter {
private static final Log log = LogFactory
.getLog(LocaleSelectionFilter.class);
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// Nothing to do at startup.
}
@Override
public void destroy() {
// Nothing to do at shutdown.
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
if (request instanceof HttpServletRequest) {
HttpServletRequest hreq = (HttpServletRequest) request;
Locale overridingLocale = SelectedLocale.getOverridingLocale(hreq);
log.debug("overriding Locale is " + overridingLocale);
if (overridingLocale != null) {
request = new LocaleSelectionRequestWrapper(hreq,
overridingLocale);
}
} else {
log.debug("Not an HttpServletRequest.");
}
chain.doFilter(request, response);
}
// ----------------------------------------------------------------------
// Helper classes
// ----------------------------------------------------------------------
/**
* Uses the selected Locale as the preferred Locale of the request.
*/
private static class LocaleSelectionRequestWrapper extends
HttpServletRequestWrapper {
private final List<Locale> locales;
@SuppressWarnings("unchecked")
public LocaleSelectionRequestWrapper(HttpServletRequest request,
Locale selectedLocale) {
super(request);
if (request == null) {
throw new NullPointerException("request may not be null.");
}
if (selectedLocale == null) {
throw new NullPointerException(
"selectedLocale may not be null.");
}
Locale selectedLanguage = new Locale(selectedLocale.getLanguage());
locales = EnumerationUtils.toList(request.getLocales());
locales.remove(selectedLanguage);
locales.add(0, selectedLanguage);
locales.remove(selectedLocale);
locales.add(0, selectedLocale);
}
@Override
public Locale getLocale() {
return locales.get(0);
}
/**
* Get the modified list of locales.
*/
@SuppressWarnings("rawtypes")
@Override
public Enumeration getLocales() {
return Collections.enumeration(locales);
}
}
}

View file

@ -0,0 +1,148 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.i18n.selection;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.commons.lang.LocaleUtils;
import org.apache.commons.lang.StringUtils;
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
/**
* Check the ConfigurationProperties for a forced locale, or for a
* comma-separate list of selectable locales.
*
* Create the appropriate Locale objects and store them in the ServletContext.
*/
public class LocaleSelectionSetup implements ServletContextListener {
/**
* If this is set, the locale is forced. No selection will be offered to the
* user, and browser locales will be ignored.
*/
public static final String PROPERTY_FORCE_LOCALE = "languages.forceLocale";
/**
* This is the list of locales that the user may select. There should be a
* national flag or symbol available for each supported locale.
*/
public static final String PROPERTY_SELECTABLE_LOCALES = "languages.selectableLocales";
private ServletContext ctx;
private StartupStatus ss;
private ConfigurationProperties props;
private String forceString;
private String selectableString;
@Override
public void contextInitialized(ServletContextEvent sce) {
ctx = sce.getServletContext();
ss = StartupStatus.getBean(ctx);
props = ConfigurationProperties.getBean(sce);
readProperties();
if (isForcing() && hasSelectables()) {
warnAboutOverride();
}
if (isForcing()) {
forceLocale();
} else if (hasSelectables()) {
setUpSelections();
} else {
reportNoLocales();
}
}
private void readProperties() {
forceString = props.getProperty(PROPERTY_FORCE_LOCALE, "");
selectableString = props.getProperty(PROPERTY_SELECTABLE_LOCALES, "");
}
private boolean isForcing() {
return StringUtils.isNotBlank(forceString);
}
private boolean hasSelectables() {
return StringUtils.isNotBlank(selectableString);
}
private void warnAboutOverride() {
ss.warning(this, "'" + PROPERTY_FORCE_LOCALE + "' will override '"
+ PROPERTY_SELECTABLE_LOCALES + "'.");
}
private void forceLocale() {
try {
Locale forceLocale = buildLocale(forceString);
SelectedLocale.setForcedLocale(ctx, forceLocale);
ssInfo("Setting forced locale to '" + forceLocale + "'.");
} catch (IllegalArgumentException e) {
ssWarning("Problem in '" + PROPERTY_FORCE_LOCALE + "': "
+ e.getMessage());
}
}
private void setUpSelections() {
List<Locale> locales = new ArrayList<Locale>();
for (String string : splitSelectables()) {
try {
locales.add(buildLocale(string));
} catch (IllegalArgumentException e) {
ssWarning("Problem in '" + PROPERTY_SELECTABLE_LOCALES + "': "
+ e.getMessage());
}
}
SelectedLocale.setSelectableLocales(ctx, locales);
ssInfo("Setting selectable locales to '" + locales + "'.");
}
private String[] splitSelectables() {
return selectableString.split("\\s*,\\s*");
}
private void reportNoLocales() {
ssInfo("There is no Locale information.");
}
private void ssInfo(String message) {
ss.info(this, message + showPropertyValues());
}
private void ssWarning(String message) {
ss.warning(this, message + showPropertyValues());
}
private String showPropertyValues() {
return " In runtime.properties, '" + PROPERTY_FORCE_LOCALE
+ "' is set to '" + forceString + "', '"
+ PROPERTY_SELECTABLE_LOCALES + "' is set to '"
+ selectableString + "'";
}
private Locale buildLocale(String localeString)
throws IllegalArgumentException {
Locale locale = LocaleUtils.toLocale(localeString);
if (!LocaleUtils.isAvailableLocale(locale)) {
ssWarning("'" + locale + "' is not a recognized locale.");
}
return locale;
}
@Override
public void contextDestroyed(ServletContextEvent arg0) {
// Nothing to do at shutdown.
}
}

View file

@ -0,0 +1,54 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.i18n.selection;
import java.io.FileNotFoundException;
import java.util.Locale;
import javax.servlet.ServletContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
/**
* Some static methods for the GUI aspects of selecting a Locale.
*/
public class LocaleSelectorUtilities {
private static final Log log = LogFactory
.getLog(LocaleSelectorUtilities.class);
/**
* Look in the current theme directory to find a selection image for this
* Locale.
*
* Images are expected at a resource path like
* /[themeDir]/i18n/images/select_locale_[locale_code].*
*
* For example, /themes/wilma/i18n/images/select_locale_en.png
* /themes/wilma/i18n/images/select_locale_en.JPEG
* /themes/wilma/i18n/images/select_locale_en.gif
*
* To create a proper URL, prepend the context path.
*/
public static String getImageUrl(VitroRequest vreq, Locale locale)
throws FileNotFoundException {
String filename = "select_locale_" + locale + ".";
String themeDir = vreq.getAppBean().getThemeDir();
String imageDirPath = "/" + themeDir + "i18n/images/";
ServletContext ctx = vreq.getSession().getServletContext();
for (Object o : ctx.getResourcePaths(imageDirPath)) {
String resourcePath = (String) o;
if (resourcePath.contains(filename)) {
String fullPath = vreq.getContextPath() + resourcePath;
log.debug("Found image for " + locale + " at '" + fullPath
+ "'");
return fullPath;
}
}
throw new FileNotFoundException("Can't find an image for " + locale);
}
}

View file

@ -0,0 +1,204 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.i18n.selection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* A utility class for storing and retrieving Locale information.
*
* The static methods create beans and store them in the ServletContext or the
* session, where the information can be found later.
*/
public abstract class SelectedLocale {
private static final Log log = LogFactory.getLog(SelectedLocale.class);
/** Use this attribute on both the ServletContext and the Session. */
protected static final String ATTRIBUTE_NAME = "SELECTED_LOCALE";
/**
* Store the forced locale in the servlet context. Clear any selectable
* Locales.
*/
public static void setForcedLocale(ServletContext ctx, Locale forcedLocale) {
log.debug("Set forced locale: " + forcedLocale);
ctx.setAttribute(ATTRIBUTE_NAME,
new ContextSelectedLocale(forcedLocale));
}
/**
* Store the selected locale in the current session.
*/
public static void setSelectedLocale(HttpServletRequest req,
Locale selectedLocale) {
log.debug("Set selected locale: " + selectedLocale);
req.getSession().setAttribute(ATTRIBUTE_NAME,
new SessionSelectedLocale(selectedLocale));
}
/**
* Do we need to override the Locale in the current request? return the
* first of these to be found:
* <ul>
* <li>The forced Locale in the servlet context</li>
* <li>The selected Locale in the session</li>
* <li>null</li>
* </ul>
*/
public static Locale getOverridingLocale(HttpServletRequest req) {
HttpSession session = req.getSession();
ServletContext ctx = session.getServletContext();
Object ctxInfo = ctx.getAttribute(ATTRIBUTE_NAME);
if (ctxInfo instanceof ContextSelectedLocale) {
Locale forcedLocale = ((ContextSelectedLocale) ctxInfo)
.getForcedLocale();
if (forcedLocale != null) {
log.debug("Found forced locale in the context: " + forcedLocale);
return forcedLocale;
}
}
Object sessionInfo = session.getAttribute(ATTRIBUTE_NAME);
if (sessionInfo instanceof SessionSelectedLocale) {
Locale selectedLocale = ((SessionSelectedLocale) sessionInfo)
.getSelectedLocale();
if (selectedLocale != null) {
log.debug("Found selected locale in the session: "
+ selectedLocale);
return selectedLocale;
}
}
return null;
}
/**
* Get the current Locale to use, which is the first of these to be found:
* <ul>
* <li>The forced Locale in the servlet context</li>
* <li>The selected Locale in the session</li>
* <li>The Locale from the request</li>
* <li>The default Locale for the JVM</li>
* </ul>
*/
public static Locale getCurrentLocale(HttpServletRequest req) {
Locale overridingLocale = getOverridingLocale(req);
if (overridingLocale != null) {
return overridingLocale;
}
Locale requestLocale = req.getLocale();
if (requestLocale != null) {
log.debug("Found locale in the request: " + requestLocale);
return requestLocale;
}
log.debug("Using default locale: " + Locale.getDefault());
return Locale.getDefault();
}
/**
* Store a list of selectable Locales in the servlet context, so we can
* easily build the selection panel in the GUI. Clears any forced locale.
*/
public static void setSelectableLocales(ServletContext ctx,
List<Locale> selectableLocales) {
log.debug("Setting selectable locales: " + selectableLocales);
ctx.setAttribute(ATTRIBUTE_NAME, new ContextSelectedLocale(
selectableLocales));
}
/**
* Get the list of selectable Locales from the servlet context. May return
* an empty list, but never returns null.
*/
public static List<Locale> getSelectableLocales(HttpServletRequest req) {
ServletContext ctx = req.getSession().getServletContext();
Object ctxInfo = ctx.getAttribute(ATTRIBUTE_NAME);
if (ctxInfo instanceof ContextSelectedLocale) {
List<Locale> selectableLocales = ((ContextSelectedLocale) ctxInfo)
.getSelectableLocales();
if (selectableLocales != null) {
log.debug("Returning selectable locales: " + selectableLocales);
return selectableLocales;
}
}
log.debug("No selectable locales were found. Returning an empty list.");
return Collections.emptyList();
}
// ----------------------------------------------------------------------
// Bean classes
// ----------------------------------------------------------------------
/** Holds Locale information in the ServletContext. */
protected static class ContextSelectedLocale {
// Only one of these is populated.
private final Locale forcedLocale;
private final List<Locale> selectableLocales;
public ContextSelectedLocale(Locale forcedLocale) {
if (forcedLocale == null) {
throw new NullPointerException("forcedLocale may not be null.");
}
this.forcedLocale = forcedLocale;
this.selectableLocales = Collections.emptyList();
}
public ContextSelectedLocale(List<Locale> selectableLocales) {
if (selectableLocales == null) {
selectableLocales = Collections.emptyList();
}
this.forcedLocale = null;
this.selectableLocales = selectableLocales;
}
public Locale getForcedLocale() {
return forcedLocale;
}
public List<Locale> getSelectableLocales() {
return selectableLocales;
}
@Override
public String toString() {
return "ContextSelectedLocale[forced=" + forcedLocale
+ ", selectable=" + selectableLocales + "]";
}
}
/** Holds Locale information in the Session. */
protected static class SessionSelectedLocale {
private final Locale selectedLocale;
public SessionSelectedLocale(Locale selectedLocale) {
this.selectedLocale = selectedLocale;
}
public Locale getSelectedLocale() {
return selectedLocale;
}
@Override
public String toString() {
return "SessionSelectedLocale[" + selectedLocale + "]";
}
}
}

View file

@ -11,7 +11,6 @@ import java.util.Comparator;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@ -42,26 +41,20 @@ public class LanguageFilteringRDFService implements RDFService {
this.langs = normalizeLangs(langs); this.langs = normalizeLangs(langs);
} }
private List<String> normalizeLangs(List<String> langs) { private List<String> normalizeLangs(List<String> langs) {
List<String> normalizedLangs = new ArrayList<String>(); log.debug("Preferred languages:" + langs);
String currentBaseLang = null;
for (String lang : langs) { List<String> normalizedLangs = new ArrayList<String>(langs);
String normalizedLang = StringUtils.lowerCase(lang); for (String lang : langs) {
String baseLang = normalizedLang.split("-")[0]; String baseLang = lang.split("-")[0];
if (currentBaseLang == null) { if (!normalizedLangs.contains(baseLang)) {
currentBaseLang = baseLang; normalizedLangs.add(baseLang);
} else if (!currentBaseLang.equals(baseLang)) { }
if (!normalizedLangs.contains(currentBaseLang)) { }
normalizedLangs.add(currentBaseLang);
} log.debug("Normalized languages:" + normalizedLangs);
currentBaseLang = baseLang; return normalizedLangs;
} }
}
if (currentBaseLang != null && !normalizedLangs.contains(currentBaseLang)) {
normalizedLangs.add(currentBaseLang);
}
return normalizedLangs;
}
@Override @Override
public boolean changeSetUpdate(ChangeSet changeSet) public boolean changeSetUpdate(ChangeSet changeSet)
@ -106,6 +99,7 @@ public class LanguageFilteringRDFService implements RDFService {
} }
private Model filterModel(Model m) { private Model filterModel(Model m) {
log.debug("filterModel");
List<Statement> retractions = new ArrayList<Statement>(); List<Statement> retractions = new ArrayList<Statement>();
StmtIterator stmtIt = m.listStatements(); StmtIterator stmtIt = m.listStatements();
while (stmtIt.hasNext()) { while (stmtIt.hasNext()) {
@ -117,6 +111,7 @@ public class LanguageFilteringRDFService implements RDFService {
continue; continue;
} }
Collections.sort(candidatesForRemoval, new StatementSortByLang()); Collections.sort(candidatesForRemoval, new StatementSortByLang());
log.debug("sorted statements: " + showSortedStatements(candidatesForRemoval));
Iterator<Statement> candIt = candidatesForRemoval.iterator(); Iterator<Statement> candIt = candidatesForRemoval.iterator();
String langRegister = null; String langRegister = null;
boolean chuckRemaining = false; boolean chuckRemaining = false;
@ -142,9 +137,27 @@ public class LanguageFilteringRDFService implements RDFService {
return m; return m;
} }
@Override private String showSortedStatements(List<Statement> candidatesForRemoval) {
List<String> langStrings = new ArrayList<String>();
for (Statement stmt: candidatesForRemoval) {
if (stmt == null) {
langStrings.add("null stmt");
} else {
RDFNode node = stmt.getObject();
if (!node.isLiteral()) {
langStrings.add("not literal");
} else {
langStrings.add(node.asLiteral().getLanguage());
}
}
}
return langStrings.toString();
}
@Override
public InputStream sparqlSelectQuery(String query, public InputStream sparqlSelectQuery(String query,
ResultFormat resultFormat) throws RDFServiceException { ResultFormat resultFormat) throws RDFServiceException {
log.debug("sparqlSelectQuery: " + query.replaceAll("\\s+", " "));
ResultSet resultSet = ResultSetFactory.fromJSON( ResultSet resultSet = ResultSetFactory.fromJSON(
s.sparqlSelectQuery(query, RDFService.ResultFormat.JSON)); s.sparqlSelectQuery(query, RDFService.ResultFormat.JSON));
List<QuerySolution> solnList = getSolutionList(resultSet); List<QuerySolution> solnList = getSolutionList(resultSet);
@ -178,6 +191,7 @@ public class LanguageFilteringRDFService implements RDFService {
continue; continue;
} }
Collections.sort(candidatesForRemoval, new RowIndexedLiteralSortByLang()); Collections.sort(candidatesForRemoval, new RowIndexedLiteralSortByLang());
log.debug("sorted RowIndexedLiterals: " + showSortedRILs(candidatesForRemoval));
Iterator<RowIndexedLiteral> candIt = candidatesForRemoval.iterator(); Iterator<RowIndexedLiteral> candIt = candidatesForRemoval.iterator();
String langRegister = null; String langRegister = null;
boolean chuckRemaining = false; boolean chuckRemaining = false;
@ -223,7 +237,15 @@ public class LanguageFilteringRDFService implements RDFService {
return new ByteArrayInputStream(outputStream.toByteArray()); return new ByteArrayInputStream(outputStream.toByteArray());
} }
private class RowIndexedLiteral { private String showSortedRILs(List<RowIndexedLiteral> candidatesForRemoval) {
List<String> langstrings = new ArrayList<String>();
for (RowIndexedLiteral ril: candidatesForRemoval) {
langstrings.add(ril.getLiteral().getLanguage());
}
return langstrings.toString();
}
private class RowIndexedLiteral {
private Literal literal; private Literal literal;
private int index; private int index;
@ -324,37 +346,44 @@ public class LanguageFilteringRDFService implements RDFService {
} }
private class LangSort { private class LangSort {
// any inexact match is worse than any exact match
private int inexactMatchPenalty = langs.size();
// no language is worse than any inexact match (if the preferred list does not include "").
private int noLanguage = 2 * inexactMatchPenalty;
// no match is worse than no language.
private int noMatch = noLanguage + 1;
protected int compareLangs(String t1lang, String t2lang) { protected int compareLangs(String t1lang, String t2lang) {
t1lang = StringUtils.lowerCase(t1lang); return languageIndex(t1lang) - languageIndex(t2lang);
t2lang = StringUtils.lowerCase(t2lang);
if ( t1lang == null && t2lang == null) {
return 0;
} else if (t1lang == null) {
return 1;
} else if (t2lang == null) {
return -1;
} else {
int t1langPref = langs.indexOf(t1lang);
int t2langPref = langs.indexOf(t2lang);
if (t1langPref == -1 && t2langPref == -1) {
if ("".equals(t1lang) && "".equals(t2lang)) {
return 0;
} else if ("".equals(t1lang) && !("".equals(t2lang))) {
return -1;
} else {
return 1;
}
} else if (t1langPref > -1 && t2langPref == -1) {
return -1;
} else if (t1langPref == -1 && t2langPref > -1) {
return 1;
} else {
return t1langPref - t2langPref;
}
}
} }
/**
* Return index of exact match, or index of partial match, or
* language-free, or no match.
*/
private int languageIndex(String lang) {
if (lang == null) {
lang = "";
}
int index = langs.indexOf(lang);
if (index >= 0) {
return index;
}
if (lang.length() > 2) {
index = langs.indexOf(lang.substring(0, 2));
if (index >= 0) {
return index + inexactMatchPenalty;
}
}
if (lang.isEmpty()) {
return noLanguage;
}
return noMatch;
}
} }
private class RowIndexedLiteralSortByLang extends LangSort implements Comparator<RowIndexedLiteral> { private class RowIndexedLiteralSortByLang extends LangSort implements Comparator<RowIndexedLiteral> {

View file

@ -90,7 +90,7 @@ public class SolrSetup implements javax.servlet.ServletContextListener{
/* setup the http connection with the solr server */ /* setup the http connection with the solr server */
String solrServerUrlString = ConfigurationProperties.getBean(sce).getProperty("vitro.local.solr.url"); String solrServerUrlString = ConfigurationProperties.getBean(sce).getProperty("vitro.local.solr.url");
if( solrServerUrlString == null ){ if( solrServerUrlString == null ){
ss.fatal(this, "Could not find vitro.local.solr.url in deploy.properties. "+ ss.fatal(this, "Could not find vitro.local.solr.url in runtime.properties. "+
"Vitro application needs a URL of a solr server that it can use to index its data. " + "Vitro application needs a URL of a solr server that it can use to index its data. " +
"It should be something like http://localhost:${port}" + context.getContextPath() + "solr" "It should be something like http://localhost:${port}" + context.getContextPath() + "solr"
); );
@ -102,7 +102,7 @@ public class SolrSetup implements javax.servlet.ServletContextListener{
solrServerUrl = new URL(solrServerUrlString); solrServerUrl = new URL(solrServerUrlString);
} catch (MalformedURLException e) { } catch (MalformedURLException e) {
ss.fatal(this, "Can't connect with the solr server. " + ss.fatal(this, "Can't connect with the solr server. " +
"The value for vitro.local.solr.url in deploy.properties is not a valid URL: " + solrServerUrlString); "The value for vitro.local.solr.url in runtime.properties is not a valid URL: " + solrServerUrlString);
return; return;
} }

View file

@ -80,7 +80,7 @@ public class ContextNodeFields implements DocumentModifier{
* @return StringBuffer with text values to add to ALLTEXT field of solr Document. * @return StringBuffer with text values to add to ALLTEXT field of solr Document.
*/ */
protected StringBuffer executeQueryForValues( Individual individual, Collection<String> queries){ protected StringBuffer executeQueryForValues( Individual individual, Collection<String> queries){
/* execute all the queries on the list and concat the values to add to all text */ /* execute all the queries on the list and concat the values to add to all text */
RDFService rdfService = rdfServiceFactory.getRDFService(); RDFService rdfService = rdfServiceFactory.getRDFService();
StringBuffer allValues = new StringBuffer(""); StringBuffer allValues = new StringBuffer("");
@ -95,7 +95,7 @@ public class ContextNodeFields implements DocumentModifier{
ResultSet results = RDFServiceUtils.sparqlSelectQuery(subInUriQuery, rdfService); ResultSet results = RDFServiceUtils.sparqlSelectQuery(subInUriQuery, rdfService);
while(results.hasNext()){ while(results.hasNext()){
valuesForQuery.append( valuesForQuery.append(
getTextForRow( results.nextSolution() ) ) ; getTextForRow( results.nextSolution(), true ) ) ;
} }
}catch(Throwable t){ }catch(Throwable t){
@ -114,7 +114,7 @@ public class ContextNodeFields implements DocumentModifier{
return allValues; return allValues;
} }
protected String getTextForRow( QuerySolution row){ protected String getTextForRow( QuerySolution row, boolean addSpace){
if( row == null ) if( row == null )
return ""; return "";
@ -124,7 +124,11 @@ public class ContextNodeFields implements DocumentModifier{
String name = iter.next(); String name = iter.next();
RDFNode node = row.get( name ); RDFNode node = row.get( name );
if( node != null ){ if( node != null ){
text.append(" ").append( node.toString() ); if(addSpace) {
text.append(" ").append( node.toString() );
} else {
text.append(node.toString());
}
}else{ }else{
log.debug(name + " is null"); log.debug(name + " is null");
} }
@ -132,7 +136,6 @@ public class ContextNodeFields implements DocumentModifier{
return text.toString(); return text.toString();
} }
public void shutdown(){ public void shutdown(){
shutdown=true; shutdown=true;
} }

View file

@ -546,7 +546,7 @@ public class JenaDataSourceSetupBase extends JenaBaseDaoCon {
if ((dns != null) && (!dns.isEmpty())) { if ((dns != null) && (!dns.isEmpty())) {
return dns; return dns;
} else { } else {
throw new IllegalStateException("deploy.properties does not " throw new IllegalStateException("runtime.properties does not "
+ "contain a value for '" + VITRO_DEFAULT_NAMESPACE + "'"); + "contain a value for '" + VITRO_DEFAULT_NAMESPACE + "'");
} }
} }

View file

@ -50,7 +50,7 @@ public class SolrSmokeTest implements ServletContextListener {
.getProperty("vitro.local.solr.url", ""); .getProperty("vitro.local.solr.url", "");
if (solrUrlString.isEmpty()) { if (solrUrlString.isEmpty()) {
ss.fatal(this, "Can't connect to Solr search engine. " ss.fatal(this, "Can't connect to Solr search engine. "
+ "deploy.properties must contain a value for " + "runtime.properties must contain a value for "
+ "vitro.local.solr.url"); + "vitro.local.solr.url");
return; return;
} }
@ -62,7 +62,7 @@ public class SolrSmokeTest implements ServletContextListener {
} catch (MalformedURLException e) { } catch (MalformedURLException e) {
ss.fatal(this, "Can't connect to Solr search engine. " ss.fatal(this, "Can't connect to Solr search engine. "
+ "The value for vitro.local.solr.url " + "The value for vitro.local.solr.url "
+ "in deploy.properties is not a valid URL: '" + "in runtime.properties is not a valid URL: '"
+ solrUrlString + "'", e); + solrUrlString + "'", e);
} }
@ -124,9 +124,7 @@ public class SolrSmokeTest implements ServletContextListener {
int status = e.getStatusCode(); int status = e.getStatusCode();
Throwable cause = e.getCause(); Throwable cause = e.getCause();
if (status == HttpStatus.SC_FORBIDDEN) { if (status == SOCKET_TIMEOUT_STATUS) {
warnForbidden();
} else if (status == SOCKET_TIMEOUT_STATUS) {
warnSocketTimeout(); warnSocketTimeout();
} else if (status != 0) { } else if (status != 0) {
warnBadHttpStatus(status); warnBadHttpStatus(status);
@ -151,23 +149,14 @@ public class SolrSmokeTest implements ServletContextListener {
ss.warning(listener, "Can't connect to the Solr search engine. " ss.warning(listener, "Can't connect to the Solr search engine. "
+ "The socket connection has repeatedly timed out. " + "The socket connection has repeatedly timed out. "
+ "Check the value of vitro.local.solr.url in " + "Check the value of vitro.local.solr.url in "
+ "deploy.properties. Is Solr responding at that URL?"); + "runtime.properties. Is Solr responding at that URL?");
}
private void warnForbidden() {
ss.warning(listener, "Can't connect to the Solr search engine. "
+ "The Solr server will not accept connections from this "
+ "host. Check the value of "
+ "vitro.local.solr.ipaddress.mask in "
+ "deploy.properties -- "
+ "does it authorize access from this IP address?");
} }
private void warnBadHttpStatus(int status) { private void warnBadHttpStatus(int status) {
ss.warning(listener, "Can't connect to the Solr search engine. " ss.warning(listener, "Can't connect to the Solr search engine. "
+ "The Solr server returned a status code of " + status + "The Solr server returned a status code of " + status
+ ". Check the value of vitro.local.solr.url in " + ". Check the value of vitro.local.solr.url in "
+ "deploy.properties."); + "runtime.properties.");
} }
private void warnProtocolViolation(HttpException e) { private void warnProtocolViolation(HttpException e) {
@ -179,7 +168,7 @@ public class SolrSmokeTest implements ServletContextListener {
ss.warning(listener, "Can't connect to the Solr search engine. '" ss.warning(listener, "Can't connect to the Solr search engine. '"
+ e.getMessage() + "' is an unknown host." + e.getMessage() + "' is an unknown host."
+ "Check the value of vitro.local.solr.url in " + "Check the value of vitro.local.solr.url in "
+ "deploy.properties.", e); + "runtime.properties.", e);
} }
private void warnConnectionRefused(ConnectException e) { private void warnConnectionRefused(ConnectException e) {
@ -187,7 +176,7 @@ public class SolrSmokeTest implements ServletContextListener {
+ "The host refused the connection. " + "The host refused the connection. "
+ "Is it possible that the port number is incorrect? " + "Is it possible that the port number is incorrect? "
+ "Check the value of vitro.local.solr.url in " + "Check the value of vitro.local.solr.url in "
+ "deploy.properties.", e); + "runtime.properties.", e);
} }
private void warnTransportError(IOException e) { private void warnTransportError(IOException e) {

View file

@ -182,10 +182,10 @@ public class UpdatePermissionSetUris implements ServletContextListener {
Journal(ServletContext ctx) throws IOException { Journal(ServletContext ctx) throws IOException {
String homeDirectoryPath = ConfigurationProperties.getBean(ctx) String homeDirectoryPath = ConfigurationProperties.getBean(ctx)
.getProperty("vitro.home.directory"); .getProperty("vitro.home");
if (homeDirectoryPath == null) { if (homeDirectoryPath == null) {
throw new IllegalStateException( throw new IllegalStateException(
"No value found for vitro.home.directory"); "No value found for vitro.home");
} }
File homeDirectory = new File(homeDirectoryPath); File homeDirectory = new File(homeDirectoryPath);
confirmIsDirectory(homeDirectory); confirmIsDirectory(homeDirectory);

View file

@ -23,7 +23,7 @@ import org.apache.commons.logging.LogFactory;
public class StartupStatus { public class StartupStatus {
private static final Log log = LogFactory.getLog(StartupStatus.class); private static final Log log = LogFactory.getLog(StartupStatus.class);
private static final String ATTRIBUTE_NAME = "STARTUP_STATUS"; protected static final String ATTRIBUTE_NAME = "STARTUP_STATUS";
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// static methods // static methods

View file

@ -59,39 +59,58 @@ public class DataGetterUtils {
* This should not return PageDataGetters and should not throw an * This should not return PageDataGetters and should not throw an
* exception if a page has PageDataGetters. * exception if a page has PageDataGetters.
*/ */
public static List<DataGetter> getDataGettersForPage( VitroRequest vreq, Model displayModel, String pageURI) public static List<DataGetter> getDataGettersForPage(VitroRequest vreq, Model displayModel, String pageURI)
throws InstantiationException, IllegalAccessException, ClassNotFoundException, IllegalArgumentException, SecurityException, InvocationTargetException, NoSuchMethodException{ throws InstantiationException, IllegalAccessException, ClassNotFoundException, IllegalArgumentException, SecurityException, InvocationTargetException, NoSuchMethodException {
//get data getter uris for pageURI List<String> dgUris = getDataGetterURIsForAssociatedURI(displayModel, pageURI);
List<String> dgUris = getDataGetterURIsForPageURI( displayModel, pageURI); List<DataGetter> dgList = dataGettersForURIs(vreq, displayModel, dgUris);
log.debug("getDataGettersForPage: " + dgList);
return dgList;
}
List<DataGetter> dgList = new ArrayList<DataGetter>(); /**
for( String dgURI: dgUris){ * Get a list of DataGetter objects that are associated with a Vitro VClass.
DataGetter dg =dataGetterForURI(vreq, displayModel, dgURI) ; * This allows the individual profile for an individual of a specific class to be returned .
if( dg != null ) */
dgList.add(dg); public static List<DataGetter> getDataGettersForClass( VitroRequest vreq, Model displayModel, String classURI)
} throws InstantiationException, IllegalAccessException, ClassNotFoundException, IllegalArgumentException, SecurityException, InvocationTargetException, NoSuchMethodException{
log.debug("getDataGettersForPage: " + dgList); List<String> dgUris = getDataGetterURIsForAssociatedURI( displayModel, classURI);
List<DataGetter> dgList = dataGettersForURIs(vreq, displayModel, dgUris);
log.debug("getDataGettersForClass: " + dgList);
return dgList; return dgList;
} }
/** /**
* Get a list of DataGetter objects that are associated with a JAVA class. * Get a list of DataGetter objects that are associated with a Freemarker template.
* This allows the individual profile for an individual of a specific class to be returned . * @param templateName a filename like "index.ftl", which will be used as a URI like "freemarker:index.ftl".
*/ */
public static List<DataGetter> getDataGettersForClass( VitroRequest vreq, Model displayModel, String classURI) public static List<DataGetter> getDataGettersForTemplate( VitroRequest vreq, Model displayModel, String templateName)
throws InstantiationException, IllegalAccessException, ClassNotFoundException, IllegalArgumentException, SecurityException, InvocationTargetException, NoSuchMethodException{ throws InstantiationException, IllegalAccessException, ClassNotFoundException, IllegalArgumentException, SecurityException, InvocationTargetException, NoSuchMethodException{
//get data getter uris for pageURI String templateUri = "freemarker:" + templateName;
List<String> dgUris = getDataGetterURIsForClassURI( displayModel, classURI); List<String> dgUris = getDataGetterURIsForAssociatedURI( displayModel, templateUri);
List<DataGetter> dgList = dataGettersForURIs(vreq, displayModel, dgUris);
log.debug("getDataGettersForTemplate '" + templateName + "': " + dgList);
return dgList;
}
List<DataGetter> dgList = new ArrayList<DataGetter>(); /**
for( String dgURI: dgUris){ * Return a list of DataGetters from the list of URIs. Each DataGetter will be configured from information
DataGetter dg =dataGetterForURI(vreq, displayModel, dgURI) ; * in the displayModel.
if( dg != null ) *
dgList.add(dg); * Problems instantiating and configuring a particular DataGetter may result in an exception,
} * or may just mean that there will be no entry in the result for that URI.
log.debug("getDataGettersForClass: " + dgList); *
return dgList; * May return an empty list, but will not return null.
} */
private static List<DataGetter> dataGettersForURIs(VitroRequest vreq, Model displayModel, List<String> dgUris)
throws InstantiationException, IllegalAccessException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException {
List<DataGetter> dgList = new ArrayList<DataGetter>();
for( String dgURI: dgUris){
DataGetter dg =dataGetterForURI(vreq, displayModel, dgURI) ;
if( dg != null )
dgList.add(dg);
}
return dgList;
}
/** /**
* Returns a DataGetter using information in the * Returns a DataGetter using information in the
@ -103,7 +122,7 @@ public class DataGetterUtils {
* that does not implement the DataGetter interface. * that does not implement the DataGetter interface.
*/ */
public static DataGetter dataGetterForURI(VitroRequest vreq, Model displayModel, String dataGetterURI) public static DataGetter dataGetterForURI(VitroRequest vreq, Model displayModel, String dataGetterURI)
throws InstantiationException, IllegalAccessException, ClassNotFoundException, IllegalArgumentException, InvocationTargetException, SecurityException, NoSuchMethodException throws InstantiationException, IllegalAccessException, ClassNotFoundException, IllegalArgumentException, InvocationTargetException, SecurityException
{ {
//get java class for dataGetterURI //get java class for dataGetterURI
String dgClassName = getJClassForDataGetterURI(displayModel, dataGetterURI); String dgClassName = getJClassForDataGetterURI(displayModel, dataGetterURI);
@ -180,47 +199,18 @@ public class DataGetterUtils {
} }
private static List<String> getDataGetterURIsForPageURI(Model displayModel, String pageURI) { private static List<String> getDataGetterURIsForAssociatedURI(Model displayModel, String associatedURI) {
String query = prefixes + String query = prefixes +
"SELECT ?dataGetter WHERE { ?pageURI display:hasDataGetter ?dataGetter. }"; "SELECT ?dataGetter WHERE { ?associatedURI display:hasDataGetter ?dataGetter }";
Query dgForPageQuery = QueryFactory.create(query); Query dgForUriQuery = QueryFactory.create(query);
QuerySolutionMap initialBindings = new QuerySolutionMap(); QuerySolutionMap initialBindings = new QuerySolutionMap();
initialBindings.add("pageURI", ResourceFactory.createResource( pageURI )); initialBindings.add("associatedURI", ResourceFactory.createResource( associatedURI ));
List<String> dgURIs = new ArrayList<String>(); List<String> dgURIs = new ArrayList<String>();
displayModel.enterCriticalSection(false); displayModel.enterCriticalSection(false);
try{ try{
QueryExecution qexec = QueryExecutionFactory.create(dgForPageQuery,displayModel,initialBindings ); QueryExecution qexec = QueryExecutionFactory.create(dgForUriQuery,displayModel,initialBindings );
try{
ResultSet results = qexec.execSelect();
while (results.hasNext()) {
QuerySolution soln = results.nextSolution();
Resource dg = soln.getResource("dataGetter");
if( dg != null && dg.getURI() != null){
dgURIs.add( dg.getURI());
}
}
}finally{ qexec.close(); }
}finally{ displayModel.leaveCriticalSection(); }
return dgURIs;
}
//Get data getters for a specific JAVA class - associates data getters with individuals for a specific JAVA class
private static List<String> getDataGetterURIsForClassURI(Model displayModel, String classURI) {
//Class URI will be substituted in so this is for a specific class uri
String query = prefixes +
"SELECT ?dataGetter WHERE { ?classURI display:hasDataGetter ?dataGetter }";
Query dgForPageQuery = QueryFactory.create(query);
QuerySolutionMap initialBindings = new QuerySolutionMap();
initialBindings.add("classURI", ResourceFactory.createResource( classURI ));
List<String> dgURIs = new ArrayList<String>();
displayModel.enterCriticalSection(false);
try{
QueryExecution qexec = QueryExecutionFactory.create(dgForPageQuery,displayModel,initialBindings );
try{ try{
ResultSet results = qexec.execSelect(); ResultSet results = qexec.execSelect();
while (results.hasNext()) { while (results.hasNext()) {
@ -233,6 +223,7 @@ public class DataGetterUtils {
}finally{ qexec.close(); } }finally{ qexec.close(); }
}finally{ displayModel.leaveCriticalSection(); } }finally{ displayModel.leaveCriticalSection(); }
log.debug("Found " + dgURIs.size() +" DataGetter URIs for '" + associatedURI + "': " + dgURIs);
return dgURIs; return dgURIs;
} }

View file

@ -9,6 +9,7 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -504,6 +505,7 @@ public class EditConfigurationTemplateModel extends BaseTemplateModel {
//TODO:Check where this logic should actually go, copied from input element formatting tag //TODO:Check where this logic should actually go, copied from input element formatting tag
//Updating to enable multiple vclasses applicable to subject to be analyzed to understand possible range of types
public Map<String, String> getOfferTypesCreateNew() { public Map<String, String> getOfferTypesCreateNew() {
WebappDaoFactory wdf = vreq.getWebappDaoFactory(); WebappDaoFactory wdf = vreq.getWebappDaoFactory();
ObjectProperty op = ObjectProperty op =
@ -513,9 +515,34 @@ public class EditConfigurationTemplateModel extends BaseTemplateModel {
wdf.getIndividualDao().getIndividualByURI(editConfig.getSubjectUri()); wdf.getIndividualDao().getIndividualByURI(editConfig.getSubjectUri());
List<VClass> vclasses = null; List<VClass> vclasses = null;
vclasses = wdf.getVClassDao().getVClassesForProperty(sub.getVClassURI(), op.getURI()); List<VClass> subjectVClasses = sub.getVClasses();
if( vclasses == null ) if( subjectVClasses == null ) {
vclasses = wdf.getVClassDao().getAllVclasses(); vclasses = wdf.getVClassDao().getAllVclasses();
}
else {
//this hash is used to make sure there are no duplicates in the vclasses
//a more elegant method may look at overriding equals/hashcode to enable a single hashset of VClass objects
HashSet<String> vclassesURIs = new HashSet<String>();
vclasses = new ArrayList<VClass>();
//Get the range vclasses applicable for the property and each vclass for the subject
for(VClass subjectVClass: subjectVClasses) {
List<VClass> rangeVclasses = wdf.getVClassDao().getVClassesForProperty(subjectVClass.getURI(), op.getURI());
//add range vclass to hash
if(rangeVclasses != null) {
for(VClass v: rangeVclasses) {
if(!vclassesURIs.contains(v.getURI())) {
vclassesURIs.add(v.getURI());
vclasses.add(v);
}
}
}
}
}
//if each subject vclass resulted in null being returned for range vclasses, then size of vclasses would be zero
if(vclasses.size() == 0) {
vclasses = wdf.getVClassDao().getAllVclasses();
}
HashMap<String,String> types = new HashMap<String, String>(); HashMap<String,String> types = new HashMap<String, String>();
for( VClass vclass : vclasses ){ for( VClass vclass : vclasses ){

View file

@ -70,7 +70,7 @@ public class OpenSocialSmokeTests implements ServletContextListener {
configProps = ConfigurationProperties.getBean(ctx); configProps = ConfigurationProperties.getBean(ctx);
/* /*
* If OpenSocial is not configured in deploy.properties, skip the tests. * If OpenSocial is not configured in runtime.properties, skip the tests.
*/ */
if (!configurationPresent()) { if (!configurationPresent()) {
ss.info(this, "The OpenSocial connection is not configured."); ss.info(this, "The OpenSocial connection is not configured.");
@ -188,7 +188,7 @@ public class OpenSocialSmokeTests implements ServletContextListener {
} }
/** /**
* Check that the Token Key file has been specified in deploy.properties, * Check that the Token Key file has been specified in runtime.properties,
* and that it actually does exist. * and that it actually does exist.
*/ */
private void checkTokenKeyFile() { private void checkTokenKeyFile() {
@ -210,14 +210,14 @@ public class OpenSocialSmokeTests implements ServletContextListener {
} }
/** /**
* Get the Token Service info from deploy.properties. It must be in the form * Get the Token Service info from runtime.properties. It must be in the form
* of host:port, and may not refer to localhost. * of host:port, and may not refer to localhost.
*/ */
private void checkTokenServiceInfo() { private void checkTokenServiceInfo() {
String tsInfo = configProps.getProperty(PROPERTY_SHINDIG_TOKEN_SERVICE); String tsInfo = configProps.getProperty(PROPERTY_SHINDIG_TOKEN_SERVICE);
if (StringUtils.isEmpty(tsInfo)) { if (StringUtils.isEmpty(tsInfo)) {
warnings.add(new Warning("There is no value for '" warnings.add(new Warning("There is no value for '"
+ PROPERTY_SHINDIG_TOKEN_SERVICE + "' in deploy.properties")); + PROPERTY_SHINDIG_TOKEN_SERVICE + "' in runtime.properties"));
return; return;
} }
@ -278,7 +278,7 @@ public class OpenSocialSmokeTests implements ServletContextListener {
private static class NoSuchPropertyException extends Exception { private static class NoSuchPropertyException extends Exception {
NoSuchPropertyException(String key) { NoSuchPropertyException(String key) {
super("There is no value for '" + key + "' in deploy.properties"); super("There is no value for '" + key + "' in build.properties");
} }
} }

View file

@ -0,0 +1,308 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp;
import static org.junit.Assert.fail;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import javax.servlet.Filter;
import javax.servlet.ServletContextListener;
import javax.servlet.http.HttpServlet;
import javax.xml.namespace.NamespaceContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.io.filefilter.NameFileFilter;
import org.apache.commons.io.filefilter.NotFileFilter;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import edu.cornell.mannlib.vitro.testing.AbstractTestClass;
/**
* Check to see that web.xml doesn't include any constructs that are permitted
* by Tomcat but prohibited by the Servlet 2.4 Specification.
*
* These are things that might not be noticed when testing Vitro on Tomcat, but
* might show up as problems on other containers like GlassFish or WebLogic.
* <ul>
* <li>
* The contents of <dispatcher/> elements must be upper-case. Tomcat permits
* lower-case, but the specification does not.</li>
* <li>
* All <servlet-class/> tags must point to existing classes. Tomcat does not try
* to load a servlet until it is necessary to service a request, but WebLogic
* loads them on startup. Either method is permitted by the specification.</li>
* </ul>
*
* As long as we're here, let's check some things that would cause Vitro to fail
* in any servlet container.
* <ul>
* <li>
* All <listener-class/> tags must point to existing classes.</li>
* <li>
* All <filter-class/> tags must point to existing classes.</li>
* <li>
* All <taglib-location/> tags must point to existing files.</li>
* </ul>
*/
@RunWith(value = Parameterized.class)
public class WebXmlTest extends AbstractTestClass {
private static final Log log = LogFactory.getLog(WebXmlTest.class);
@Parameters
public static Collection<Object[]> findWebXmlFiles() {
IOFileFilter fileFilter = new NameFileFilter("web.xml");
IOFileFilter dirFilter = new NotFileFilter(new NameFileFilter(".build"));
Collection<File> files = FileUtils.listFiles(new File("."), fileFilter,
dirFilter);
if (files.isEmpty()) {
System.out.println("WARNING: could not find web.xml");
} else {
if (files.size() > 1) {
System.out
.println("WARNING: testing more than one web.xml file: "
+ files);
}
}
Collection<Object[]> parameters = new ArrayList<Object[]>();
for (File file : files) {
parameters.add(new Object[] { file });
}
return parameters;
}
private static DocumentBuilder docBuilder = createDocBuilder();
private static XPath xpath = createXPath();
private static DocumentBuilder createDocBuilder() {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory
.newInstance();
factory.setNamespaceAware(true); // never forget this!
return factory.newDocumentBuilder();
} catch (ParserConfigurationException e) {
throw new RuntimeException(e);
}
}
private static XPath createXPath() {
XPath xp = XPathFactory.newInstance().newXPath();
xp.setNamespaceContext(new StupidNamespaceContext());
return xp;
}
private File webXmlFile;
private Document webXmlDoc;
private List<String> messages = new ArrayList<String>();
public WebXmlTest(File file) {
this.webXmlFile = file;
}
@Before
public void parseWebXml() throws SAXException, IOException {
if (webXmlDoc == null) {
webXmlDoc = docBuilder.parse(webXmlFile);
}
}
@Test
public void checkAll() throws IOException {
checkDispatcherValues();
checkServletClasses();
checkListenerClasses();
checkFilterClasses();
checkTaglibLocations();
if (!messages.isEmpty()) {
for (String message : messages) {
System.out.println(message);
}
fail("Found these problems with '" + webXmlFile.getCanonicalPath()
+ "'\n " + StringUtils.join(messages, "\n "));
}
}
private void checkDispatcherValues() {
List<String> okValues = Arrays.asList(new String[] { "FORWARD",
"REQUEST", "INCLUDE", "ERROR" });
for (Node n : findNodes("//j2ee:dispatcher")) {
String text = n.getTextContent();
if (!okValues.contains(text)) {
messages.add("<dispatcher>" + text
+ "</dispatcher> is not valid. Acceptable values are "
+ okValues);
}
}
}
private void checkServletClasses() {
for (Node n : findNodes("//j2ee:servlet-class")) {
String text = n.getTextContent();
String problem = confirmClassNameIsValid(text, HttpServlet.class);
if (problem != null) {
messages.add("<servlet-class>" + text
+ "</servlet-class> is not valid: " + problem);
}
}
}
private void checkListenerClasses() {
for (Node n : findNodes("//j2ee:listener-class")) {
String text = n.getTextContent();
String problem = confirmClassNameIsValid(text,
ServletContextListener.class);
if (problem != null) {
messages.add("<listener-class>" + text
+ "</listener-class> is not valid: " + problem);
}
}
}
private void checkFilterClasses() {
for (Node n : findNodes("//j2ee:filter-class")) {
String text = n.getTextContent();
String problem = confirmClassNameIsValid(text, Filter.class);
if (problem != null) {
messages.add("<filter-class>" + text
+ "</filter-class> is not valid: " + problem);
}
}
}
private void checkTaglibLocations() {
// TODO Don't know how to do this one. Where do we look for the taglibs?
}
// ----------------------------------------------------------------------
// Helper methods
// ----------------------------------------------------------------------
/**
* Search for an Xpath, returning a handy list.
*/
private List<Node> findNodes(String pattern) {
try {
XPathExpression xpe = xpath.compile(pattern);
NodeList nodes = (NodeList) xpe.evaluate(
webXmlDoc.getDocumentElement(), XPathConstants.NODESET);
List<Node> list = new ArrayList<Node>();
for (int i = 0; i < nodes.getLength(); i++) {
list.add(nodes.item(i));
}
return list;
} catch (XPathExpressionException e) {
throw new RuntimeException(e);
}
}
/**
* Check that the supplied className can be instantiated with a
* zero-argument constructor, and assigned to a variable of the target
* class.
*/
private String confirmClassNameIsValid(String className,
Class<?> targetClass) {
try {
Class<?> specifiedClass = Class.forName(className);
Object o = specifiedClass.newInstance();
if (!targetClass.isInstance(o)) {
return specifiedClass.getSimpleName()
+ " is not a subclass of "
+ targetClass.getSimpleName() + ".";
}
} catch (ClassNotFoundException e) {
return "The class does not exist.";
} catch (InstantiationException e) {
return "The class does not have a public constructor "
+ "that takes zero arguments.";
} catch (IllegalAccessException e) {
return "The class does not have a public constructor "
+ "that takes zero arguments.";
}
return null;
}
/**
* Dump the first 20 nodes of an XML context, excluding comments and blank
* text nodes.
*/
@SuppressWarnings("unused")
private int dumpXml(Node xmlNode, int... parms) {
int remaining = (parms.length == 0) ? 20 : parms[0];
int level = (parms.length < 2) ? 1 : parms[1];
Node n = xmlNode;
if (Node.COMMENT_NODE == n.getNodeType()) {
return 0;
}
if (Node.TEXT_NODE == n.getNodeType()) {
if (StringUtils.isBlank(n.getTextContent())) {
return 0;
}
}
int used = 1;
System.out.println(StringUtils.repeat("-->", level) + n);
NodeList nl = n.getChildNodes();
for (int i = 0; (i < nl.getLength() && remaining > used); i++) {
used += dumpXml(nl.item(i), remaining - used, level + 1);
}
return used;
}
// ----------------------------------------------------------------------
// Helper classes
// ----------------------------------------------------------------------
private static class StupidNamespaceContext implements NamespaceContext {
@Override
public String getNamespaceURI(String prefix) {
if ("j2ee".equals(prefix)) {
return "http://java.sun.com/xml/ns/j2ee";
} else {
throw new UnsupportedOperationException();
}
}
@Override
public String getPrefix(String namespaceURI) {
throw new UnsupportedOperationException();
}
@Override
public Iterator<?> getPrefixes(String namespaceURI) {
throw new UnsupportedOperationException();
}
}
}

View file

@ -52,15 +52,6 @@ public class IndividualRequestAnalyzerTest extends AbstractTestClass {
private static final String URL_BYTESTREAM_ALIAS = URL_HOME_PAGE + "/file/" private static final String URL_BYTESTREAM_ALIAS = URL_HOME_PAGE + "/file/"
+ ID_FILE_BYTESTREAM + "/" + BYTESTREAM_FILENAME; + ID_FILE_BYTESTREAM + "/" + BYTESTREAM_FILENAME;
/**
* Info about an individual that appears in a different namespace.
*/
private static final String SOME_PREFIX = "somePrefix";
private static final String SOME_NAMESPACE = "http://some.namespace/";
private static final String ID_INDIVIDUAL_FOREIGN = "foreignId";
private static final String URI_INDIVIDUAL_FOREIGN = SOME_NAMESPACE
+ ID_INDIVIDUAL_FOREIGN;
private IndividualRequestAnalyzer analyzer; private IndividualRequestAnalyzer analyzer;
private IndividualRequestAnalysisContextStub analysisContext; private IndividualRequestAnalysisContextStub analysisContext;
private HttpServletRequestStub req; private HttpServletRequestStub req;
@ -69,7 +60,6 @@ public class IndividualRequestAnalyzerTest extends AbstractTestClass {
private IndividualStub testIndividual; private IndividualStub testIndividual;
private IndividualStub bytestreamIndividual; private IndividualStub bytestreamIndividual;
private IndividualStub foreignIndividual;
@Before @Before
public void setup() { public void setup() {
@ -83,10 +73,6 @@ public class IndividualRequestAnalyzerTest extends AbstractTestClass {
bytestreamIndividual = new IndividualStub(URI_FILE_BYTESTREAM); bytestreamIndividual = new IndividualStub(URI_FILE_BYTESTREAM);
analysisContext.addIndividual(bytestreamIndividual); analysisContext.addIndividual(bytestreamIndividual);
analysisContext.setAliasUrl(URI_FILE_BYTESTREAM, URL_BYTESTREAM_ALIAS); analysisContext.setAliasUrl(URI_FILE_BYTESTREAM, URL_BYTESTREAM_ALIAS);
foreignIndividual = new IndividualStub(URI_INDIVIDUAL_FOREIGN);
analysisContext.addIndividual(foreignIndividual);
analysisContext.setNamespacePrefix(SOME_PREFIX, SOME_NAMESPACE);
} }
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
@ -132,16 +118,6 @@ public class IndividualRequestAnalyzerTest extends AbstractTestClass {
assertDefaultRequestInfo("find by display path", URI_INDIVIDUAL_TEST); assertDefaultRequestInfo("find by display path", URI_INDIVIDUAL_TEST);
} }
/** /individual/nsPrefix/localname */
@Test
public void findByPrefixAndLocalname() {
req.setRequestUrl(url(DEFAULT_NAMESPACE + SOME_PREFIX + "/"
+ ID_INDIVIDUAL_FOREIGN));
analyzeIt();
assertDefaultRequestInfo("find by prefix and localname",
URI_INDIVIDUAL_FOREIGN);
}
/** /individual/a/b/c fails. */ /** /individual/a/b/c fails. */
@Test @Test
public void unrecognizedPath() { public void unrecognizedPath() {

View file

@ -0,0 +1,314 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.i18n.selection;
import static edu.cornell.mannlib.vitro.webapp.i18n.selection.LocaleSelectionSetup.PROPERTY_FORCE_LOCALE;
import static edu.cornell.mannlib.vitro.webapp.i18n.selection.LocaleSelectionSetup.PROPERTY_SELECTABLE_LOCALES;
import static edu.cornell.mannlib.vitro.webapp.i18n.selection.SelectedLocale.ATTRIBUTE_NAME;
import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import javax.servlet.ServletContextEvent;
import org.apache.commons.lang.LocaleUtils;
import org.apache.commons.lang.ObjectUtils;
import org.apache.log4j.Level;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import stubs.edu.cornell.mannlib.vitro.webapp.config.ConfigurationPropertiesStub;
import stubs.edu.cornell.mannlib.vitro.webapp.startup.StartupStatusStub;
import stubs.javax.servlet.ServletContextStub;
import edu.cornell.mannlib.vitro.testing.AbstractTestClass;
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
import edu.cornell.mannlib.vitro.webapp.i18n.selection.SelectedLocale.ContextSelectedLocale;
/**
* TODO
*/
public class LocaleSelectionSetupTest extends AbstractTestClass {
// ----------------------------------------------------------------------
// Infrastructure
// ----------------------------------------------------------------------
private LocaleSelectionSetup lss;
private ServletContextStub ctx;
private ServletContextEvent sce;
private ConfigurationPropertiesStub props;
private StartupStatusStub ss;
private int[] expectedMessageCounts;
private Locale expectedForcedLocale;
private List<Locale> expectedSelectableLocales;
@Before
public void setup() {
// setLoggerLevel(LocaleSelectionSetup.class, Level.DEBUG);
// setLoggerLevel(StartupStatusStub.class, Level.DEBUG);
setLoggerLevel(ConfigurationProperties.class, Level.WARN);
ctx = new ServletContextStub();
sce = new ServletContextEvent(ctx);
props = new ConfigurationPropertiesStub();
props.setBean(ctx);
ss = new StartupStatusStub(ctx);
lss = new LocaleSelectionSetup();
}
@After
public void checkExpectations() {
if (expectedMessageCounts == null) {
fail("expecteMessages() was not called");
}
String message = compareMessageCount("info", ss.getInfoCount(),
expectedMessageCounts[0])
+ compareMessageCount("warning", ss.getWarningCount(),
expectedMessageCounts[1])
+ compareMessageCount("fatal", ss.getFatalCount(),
expectedMessageCounts[2])
+ checkForced()
+ checkSelectable();
if (!message.isEmpty()) {
fail(message);
}
}
private String compareMessageCount(String label, int actual, int expected) {
if (expected == actual) {
return "";
} else {
return "expecting " + expected + " " + label
+ " messages, but received " + actual + "; ";
}
}
private String checkForced() {
Locale actual = null;
Object o = ctx.getAttribute(ATTRIBUTE_NAME);
if (o instanceof ContextSelectedLocale) {
actual = ((ContextSelectedLocale) o).getForcedLocale();
}
Locale expected = expectedForcedLocale;
if (ObjectUtils.equals(expected, actual)) {
return "";
} else {
return "expected forced locale of " + expectedForcedLocale
+ ", but was " + actual + "; ";
}
}
private String checkSelectable() {
List<Locale> actual = Collections.emptyList();
Object o = ctx.getAttribute(ATTRIBUTE_NAME);
if (o instanceof ContextSelectedLocale) {
actual = ((ContextSelectedLocale) o).getSelectableLocales();
}
List<Locale> expected = expectedSelectableLocales;
if (expected == null) {
expected = Collections.emptyList();
}
if (ObjectUtils.equals(expected, actual)) {
return "";
} else {
return "expected selectable locales of " + expected + ", but was "
+ actual + "; ";
}
}
// ----------------------------------------------------------------------
// The tests
// ----------------------------------------------------------------------
// General functionality
@Test
public void neitherPropertyIsSpecified() {
lss.contextInitialized(sce);
expectMessages(1, 0, 0);
}
@Test
public void forceSuccessL() {
props.setProperty(PROPERTY_FORCE_LOCALE, "es");
lss.contextInitialized(sce);
expectForced("es");
expectMessages(1, 0, 0);
}
@Test
public void forceSuccessL_C() {
props.setProperty(PROPERTY_FORCE_LOCALE, "es_ES");
lss.contextInitialized(sce);
expectForced("es_ES");
expectMessages(1, 0, 0);
}
@Test
public void forceSuccessL_C_V() {
props.setProperty(PROPERTY_FORCE_LOCALE, "no_NO_NY");
lss.contextInitialized(sce);
expectForced("no_NO_NY");
expectMessages(1, 0, 0);
}
@Test
public void oneSelectable() {
props.setProperty(PROPERTY_SELECTABLE_LOCALES, "fr_FR");
lss.contextInitialized(sce);
expectSelectable("fr_FR");
expectMessages(1, 0, 0);
}
@Test
public void twoSelectables() {
props.setProperty(PROPERTY_SELECTABLE_LOCALES, "fr_FR, es_PE");
lss.contextInitialized(sce);
expectSelectable("fr_FR", "es_PE");
expectMessages(1, 0, 0);
}
@Test
public void bothPropertiesAreSpecified() {
props.setProperty(PROPERTY_FORCE_LOCALE, "es_ES");
props.setProperty(PROPERTY_SELECTABLE_LOCALES, "fr_FR");
lss.contextInitialized(sce);
expectForced("es_ES");
expectMessages(1, 1, 0);
}
// Locale string syntax (common to both force and selectable)
@Test
public void langaugeIsEmpty() {
props.setProperty(PROPERTY_FORCE_LOCALE, "_ES");
lss.contextInitialized(sce);
expectMessages(0, 1, 0);
}
@Test
public void languageWrongLength() {
props.setProperty(PROPERTY_FORCE_LOCALE, "e_ES");
lss.contextInitialized(sce);
expectMessages(0, 1, 0);
}
@Test
public void languageNotAlphabetic() {
props.setProperty(PROPERTY_FORCE_LOCALE, "e4_ES");
lss.contextInitialized(sce);
expectMessages(0, 1, 0);
}
@Test
public void languageNotLowerCase() {
props.setProperty(PROPERTY_FORCE_LOCALE, "eS_ES");
lss.contextInitialized(sce);
expectMessages(0, 1, 0);
}
@Test
public void countryIsEmpty() {
props.setProperty(PROPERTY_FORCE_LOCALE, "es_ _13");
lss.contextInitialized(sce);
expectMessages(0, 1, 0);
}
@Test
public void countryWrongLength() {
props.setProperty(PROPERTY_FORCE_LOCALE, "es_ESS");
lss.contextInitialized(sce);
expectMessages(0, 1, 0);
}
@Test
public void countryNotAlphabetic() {
props.setProperty(PROPERTY_FORCE_LOCALE, "es_E@");
lss.contextInitialized(sce);
expectMessages(0, 1, 0);
}
@Test
public void countryNotUpperCase() {
props.setProperty(PROPERTY_FORCE_LOCALE, "es_es");
lss.contextInitialized(sce);
expectMessages(0, 1, 0);
}
@Test
public void variantIsEmpty() {
props.setProperty(PROPERTY_FORCE_LOCALE, "es_ES_");
lss.contextInitialized(sce);
expectMessages(0, 1, 0);
}
@Test
public void funkyVariantIsAcceptable() {
props.setProperty(PROPERTY_FORCE_LOCALE, "es_ES_123_aa");
lss.contextInitialized(sce);
expectForced("es_ES_123_aa");
expectMessages(1, 1, 0);
}
@Test
public void localeNotRecognizedProducesWarning() {
props.setProperty(PROPERTY_FORCE_LOCALE, "es_FR");
lss.contextInitialized(sce);
expectForced("es_FR");
expectMessages(1, 1, 0);
}
// Syntax of selectable property
@Test
public void emptySelectableLocaleProducesWarning() {
props.setProperty(PROPERTY_SELECTABLE_LOCALES, "es_ES, , fr_FR");
lss.contextInitialized(sce);
expectSelectable("es_ES", "fr_FR");
expectMessages(1, 1, 0);
}
@Test
public void blanksAroundCommasAreIgnored() {
props.setProperty(PROPERTY_SELECTABLE_LOCALES, "es_ES,en_US \t , fr_FR");
lss.contextInitialized(sce);
expectSelectable("es_ES", "en_US", "fr_FR");
expectMessages(1, 0, 0);
}
// ----------------------------------------------------------------------
// helper methods
// ----------------------------------------------------------------------
private void expectMessages(int infoCount, int warningCount, int fatalCount) {
this.expectedMessageCounts = new int[] { infoCount, warningCount,
fatalCount };
}
private void expectForced(String localeString) {
this.expectedForcedLocale = stringToLocale(localeString);
}
private void expectSelectable(String... strings) {
List<Locale> list = new ArrayList<Locale>();
for (String string : strings) {
list.add(stringToLocale(string));
}
this.expectedSelectableLocales = list;
}
private Locale stringToLocale(String string) {
return LocaleUtils.toLocale(string);
}
}

View file

@ -0,0 +1,309 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.rdfservice.filter;
import static org.junit.Assert.assertEquals;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.Level;
import org.junit.Before;
import org.junit.Test;
import stubs.com.hp.hpl.jena.rdf.model.LiteralStub;
import com.hp.hpl.jena.rdf.model.Literal;
import edu.cornell.mannlib.vitro.testing.AbstractTestClass;
/**
* This is the matching order we expect to see:
*
* <pre>
* exact match to preferred, by order.
* partial match to preferred, by order.
* vanilla or null (no language)
* no match
* </pre>
*/
public class LanguageFilteringRDFServiceTest extends AbstractTestClass {
private static final Log log = LogFactory
.getLog(LanguageFilteringRDFServiceTest.class);
private static final String COLLATOR_CLASSNAME = "edu.cornell.mannlib.vitro.webapp.rdfservice.filter.LanguageFilteringRDFService$RowIndexedLiteralSortByLang";
private static final String RIL_CLASSNAME = "edu.cornell.mannlib.vitro.webapp.rdfservice.filter.LanguageFilteringRDFService$RowIndexedLiteral";
private LanguageFilteringRDFService filteringRDFService;
private List<Object> listOfRowIndexedLiterals;
private int literalIndex;
private List<String> preferredLanguages;
private List<String> availableLanguages;
private List<String> expectedSortOrders;
@Before
public void setup() {
setLoggerLevel(this.getClass(), Level.DEBUG);
setLoggerLevel(LanguageFilteringRDFService.class, Level.DEBUG);
}
// ----------------------------------------------------------------------
// The tests
// ----------------------------------------------------------------------
@Test
public void singleMatch() {
preferredLanguages = list("en-US");
availableLanguages = list("en-US");
expectedSortOrders = list("en-US");
testArbitraryOrder();
}
@Test
public void singleNoMatch() {
preferredLanguages = list("en-US");
availableLanguages = list("es-MX");
expectedSortOrders = list("es-MX");
testArbitraryOrder();
}
@Test
public void doubleMatch() {
preferredLanguages = list("en-US", "es-MX");
availableLanguages = list("en-US", "es-MX");
expectedSortOrders = list("en-US", "es-MX");
testBothWays();
}
@Test
public void noMatches() {
preferredLanguages = list("es-MX");
availableLanguages = list("en-US", "fr-FR");
expectedSortOrders = list("en-US", "fr-FR");
testArbitraryOrder();
}
@Test
public void partialMatches() {
preferredLanguages = list("en", "es");
availableLanguages = list("en-US", "es-MX");
expectedSortOrders = list("en-US", "es-MX");
testBothWays();
}
@Test
public void matchIsBetterThanNoMatch() {
preferredLanguages = list("en-US", "es-MX");
availableLanguages = list("en-US", "fr-FR");
expectedSortOrders = list("en-US", "fr-FR");
testBothWays();
}
@Test
public void matchIsBetterThanPartialMatch() {
preferredLanguages = list("es-ES", "en-US");
availableLanguages = list("en-US", "es-MX");
expectedSortOrders = list("en-US", "es-MX");
testBothWays();
}
@Test
public void exactMatchIsBetterThanPartialMatch() {
preferredLanguages = list("es");
availableLanguages = list("es", "es-MX");
expectedSortOrders = list("es", "es-MX");
testBothWays();
}
@Test
public void matchIsBetterThanVanilla() {
preferredLanguages = list("en-US");
availableLanguages = list("en-US", "");
expectedSortOrders = list("en-US", "");
testBothWays();
}
@Test
public void partialMatchIsBetterThanVanilla() {
preferredLanguages = list("es-MX");
availableLanguages = list("es-ES", "");
expectedSortOrders = list("es-ES", "");
testBothWays();
}
@Test
public void vanillaIsBetterThanNoMatch() {
preferredLanguages = list("es-MX");
availableLanguages = list("en-US", "");
expectedSortOrders = list("", "en-US");
testBothWays();
}
@Test
public void omnibus() {
preferredLanguages = list("es-MX", "es", "en-UK", "es-PE", "fr");
availableLanguages = list("es-MX", "es", "fr", "es-ES", "fr-FR", "",
"de-DE");
expectedSortOrders = list("es-MX", "es", "fr", "es-ES", "fr-FR", "",
"de-DE");
testBothWays();
}
// ----------------------------------------------------------------------
// Helper methods
// ----------------------------------------------------------------------
/**
* Sort the available languages as they are presented. Then reverse them and
* sort again.
*/
private void testBothWays() {
createLanguageFilter();
buildListOfLiterals();
sortListOfLiterals();
assertLanguageOrder("sort literals");
buildReversedListOfLiterals();
sortListOfLiterals();
assertLanguageOrder("sort reversed literals");
}
/**
* Sort the available languages, without caring what the eventual sorted
* order is. Really, this is just a test to see that no exceptions are
* thrown, and no languages are "lost in translation".
*/
private void testArbitraryOrder() {
createLanguageFilter();
buildListOfLiterals();
sortListOfLiterals();
assertLanguages("sort literals");
buildReversedListOfLiterals();
sortListOfLiterals();
assertLanguages("sort reversed literals");
}
private List<String> list(String... strings) {
return new ArrayList<String>(Arrays.asList(strings));
}
private void createLanguageFilter() {
filteringRDFService = new LanguageFilteringRDFService(null,
preferredLanguages);
}
private void buildListOfLiterals() {
List<Object> list = new ArrayList<Object>();
for (String language : availableLanguages) {
list.add(buildRowIndexedLiteral(language));
}
listOfRowIndexedLiterals = list;
}
private void buildReversedListOfLiterals() {
List<Object> list = new ArrayList<Object>();
for (String language : availableLanguages) {
list.add(0, buildRowIndexedLiteral(language));
}
listOfRowIndexedLiterals = list;
}
private void sortListOfLiterals() {
log.debug("before sorting: "
+ languagesFromLiterals(listOfRowIndexedLiterals));
Comparator<Object> comparator = buildRowIndexedLiteralSortByLang();
Collections.sort(listOfRowIndexedLiterals, comparator);
}
private void assertLanguageOrder(String message) {
List<String> expectedLanguages = expectedSortOrders;
log.debug("expected order: " + expectedLanguages);
List<String> actualLanguages = languagesFromLiterals(listOfRowIndexedLiterals);
log.debug("actual order: " + actualLanguages);
assertEquals(message, expectedLanguages, actualLanguages);
}
private void assertLanguages(String message) {
Set<String> expectedLanguages = new HashSet<String>(expectedSortOrders);
log.debug("expected languages: " + expectedLanguages);
Set<String> actualLanguages = new HashSet<String>(
languagesFromLiterals(listOfRowIndexedLiterals));
log.debug("actual languages: " + actualLanguages);
assertEquals(message, expectedLanguages, actualLanguages);
}
private List<String> languagesFromLiterals(List<Object> literals) {
List<String> actualLanguages = new ArrayList<String>();
for (Object ril : literals) {
actualLanguages.add(getLanguageFromRowIndexedLiteral(ril));
}
return actualLanguages;
}
// ----------------------------------------------------------------------
// Reflection methods to get around "private" declarations.
// ----------------------------------------------------------------------
private Object buildRowIndexedLiteral(String language) {
try {
Class<?> clazz = Class.forName(RIL_CLASSNAME);
Class<?>[] argTypes = { LanguageFilteringRDFService.class,
Literal.class, Integer.TYPE };
Constructor<?> constructor = clazz.getDeclaredConstructor(argTypes);
constructor.setAccessible(true);
Literal l = new LiteralStub(language);
int i = literalIndex++;
return constructor.newInstance(filteringRDFService, l, i);
} catch (Exception e) {
throw new RuntimeException(
"Could not create a row-indexed literal", e);
}
}
@SuppressWarnings("unchecked")
private Comparator<Object> buildRowIndexedLiteralSortByLang() {
try {
Class<?> clazz = Class.forName(COLLATOR_CLASSNAME);
Class<?>[] argTypes = { LanguageFilteringRDFService.class };
Constructor<?> constructor = clazz.getDeclaredConstructor(argTypes);
constructor.setAccessible(true);
return (Comparator<Object>) constructor
.newInstance(filteringRDFService);
} catch (Exception e) {
throw new RuntimeException("Could not create a collator", e);
}
}
private String getLanguageFromRowIndexedLiteral(Object ril) {
try {
Method m = ril.getClass().getDeclaredMethod("getLiteral");
m.setAccessible(true);
Literal l = (Literal) m.invoke(ril);
return l.getLanguage();
} catch (Exception e) {
throw new RuntimeException(
"Could not get the Literal from a RowIndexedLiteral", e);
}
}
}

View file

@ -0,0 +1,179 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package stubs.com.hp.hpl.jena.rdf.model;
import com.hp.hpl.jena.datatypes.RDFDatatype;
import com.hp.hpl.jena.graph.Node;
import com.hp.hpl.jena.rdf.model.Literal;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.RDFVisitor;
import com.hp.hpl.jena.rdf.model.Resource;
/**
* Only implemented what I needed so far. The rest is left as an exercise for
* the student.
*/
public class LiteralStub implements Literal {
// ----------------------------------------------------------------------
// Stub infrastructure
// ----------------------------------------------------------------------
final String language;
public LiteralStub(String language) {
this.language = language;
}
// ----------------------------------------------------------------------
// Stub methods
// ----------------------------------------------------------------------
@Override
public boolean isLiteral() {
return true;
}
@Override
public boolean isAnon() {
return false;
}
@Override
public boolean isResource() {
return false;
}
@Override
public boolean isURIResource() {
return false;
}
@Override
public Literal asLiteral() {
return this;
}
@Override
public Resource asResource() {
throw new ClassCastException();
}
@Override
public String getLanguage() {
return language;
}
// ----------------------------------------------------------------------
// Un-implemented methods
// ----------------------------------------------------------------------
@Override
public <T extends RDFNode> T as(Class<T> view) {
throw new RuntimeException("LiteralStub.as() not implemented.");
}
@Override
public <T extends RDFNode> boolean canAs(Class<T> arg0) {
throw new RuntimeException("LiteralStub.canAs() not implemented.");
}
@Override
public Model getModel() {
throw new RuntimeException("LiteralStub.getModel() not implemented.");
}
@Override
public Object visitWith(RDFVisitor arg0) {
throw new RuntimeException("LiteralStub.visitWith() not implemented.");
}
@Override
public Node asNode() {
throw new RuntimeException("LiteralStub.asNode() not implemented.");
}
@Override
public boolean getBoolean() {
throw new RuntimeException("LiteralStub.getBoolean() not implemented.");
}
@Override
public byte getByte() {
throw new RuntimeException("LiteralStub.getByte() not implemented.");
}
@Override
public char getChar() {
throw new RuntimeException("LiteralStub.getChar() not implemented.");
}
@Override
public RDFDatatype getDatatype() {
throw new RuntimeException("LiteralStub.getDatatype() not implemented.");
}
@Override
public String getDatatypeURI() {
throw new RuntimeException(
"LiteralStub.getDatatypeURI() not implemented.");
}
@Override
public double getDouble() {
throw new RuntimeException("LiteralStub.getDouble() not implemented.");
}
@Override
public float getFloat() {
throw new RuntimeException("LiteralStub.getFloat() not implemented.");
}
@Override
public int getInt() {
throw new RuntimeException("LiteralStub.getInt() not implemented.");
}
@Override
public String getLexicalForm() {
throw new RuntimeException(
"LiteralStub.getLexicalForm() not implemented.");
}
@Override
public long getLong() {
throw new RuntimeException("LiteralStub.getLong() not implemented.");
}
@Override
public short getShort() {
throw new RuntimeException("LiteralStub.getShort() not implemented.");
}
@Override
public String getString() {
throw new RuntimeException("LiteralStub.getString() not implemented.");
}
@Override
public Object getValue() {
throw new RuntimeException("LiteralStub.getValue() not implemented.");
}
@Override
public Literal inModel(Model arg0) {
throw new RuntimeException("LiteralStub.inModel() not implemented.");
}
@Override
public boolean isWellFormedXML() {
throw new RuntimeException(
"LiteralStub.isWellFormedXML() not implemented.");
}
@Override
public boolean sameValueAs(Literal arg0) {
throw new RuntimeException("LiteralStub.sameValueAs() not implemented.");
}
}

View file

@ -21,7 +21,6 @@ public class IndividualRequestAnalysisContextStub implements
private final String defaultNamespace; private final String defaultNamespace;
private final Map<String, Individual> individualsByUri = new HashMap<String, Individual>(); private final Map<String, Individual> individualsByUri = new HashMap<String, Individual>();
private final Map<String, Individual> profilePages = new HashMap<String, Individual>(); private final Map<String, Individual> profilePages = new HashMap<String, Individual>();
private final Map<String, String> namespacesByPrefix = new HashMap<String, String>();
private final Map<String, String> aliasUrlsByIndividual = new HashMap<String, String>(); private final Map<String, String> aliasUrlsByIndividual = new HashMap<String, String>();
public IndividualRequestAnalysisContextStub(String defaultNamespace) { public IndividualRequestAnalysisContextStub(String defaultNamespace) {
@ -36,10 +35,6 @@ public class IndividualRequestAnalysisContextStub implements
profilePages.put(netId, individual); profilePages.put(netId, individual);
} }
public void setNamespacePrefix(String prefix, String namespace) {
namespacesByPrefix.put(prefix, namespace);
}
public void setAliasUrl(String individualUri, String aliasUrl) { public void setAliasUrl(String individualUri, String aliasUrl) {
aliasUrlsByIndividual.put(individualUri, aliasUrl); aliasUrlsByIndividual.put(individualUri, aliasUrl);
} }
@ -53,15 +48,6 @@ public class IndividualRequestAnalysisContextStub implements
return defaultNamespace; return defaultNamespace;
} }
@Override
public String getNamespaceForPrefix(String prefix) {
if (prefix == null) {
return "";
}
String namespace = namespacesByPrefix.get(prefix);
return (namespace == null) ? "" : namespace;
}
@Override @Override
public Individual getIndividualByURI(String individualUri) { public Individual getIndividualByURI(String individualUri) {
if (individualUri == null) { if (individualUri == null) {

View file

@ -0,0 +1,140 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package stubs.edu.cornell.mannlib.vitro.webapp.startup;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextListener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
/**
* Keep track of how many messages come in.
*/
public class StartupStatusStub extends StartupStatus {
private static final Log log = LogFactory.getLog(StartupStatusStub.class);
// ----------------------------------------------------------------------
// Stub infrastructure
// ----------------------------------------------------------------------
private int infoCount = 0;
private int warningCount = 0;
private int fatalCount = 0;
public StartupStatusStub(ServletContext ctx) {
ctx.setAttribute(ATTRIBUTE_NAME, this);
}
public int getInfoCount() {
return infoCount;
}
public int getWarningCount() {
return warningCount;
}
public int getFatalCount() {
return fatalCount;
}
// ----------------------------------------------------------------------
// Stub methods
// ----------------------------------------------------------------------
@Override
public void info(ServletContextListener listener, String message) {
log.debug("INFO: " + message);
infoCount++;
}
@Override
public void info(ServletContextListener listener, String message,
Throwable cause) {
log.debug("INFO: " + message + " " + cause);
infoCount++;
}
@Override
public void warning(ServletContextListener listener, String message) {
log.debug("WARNING: " + message);
warningCount++;
}
@Override
public void warning(ServletContextListener listener, String message,
Throwable cause) {
log.debug("WARNING: " + message + " " + cause);
warningCount++;
}
@Override
public void fatal(ServletContextListener listener, String message) {
log.debug("FATAL: " + message);
fatalCount++;
}
@Override
public void fatal(ServletContextListener listener, String message,
Throwable cause) {
log.debug("FATAL: " + message + " " + cause);
fatalCount++;
}
// ----------------------------------------------------------------------
// Un-implemented methods
// ----------------------------------------------------------------------
@Override
public void listenerNotExecuted(ServletContextListener listener) {
throw new RuntimeException(
"StartupStatusStub.listenerNotExecuted() not implemented.");
}
@Override
public void listenerExecuted(ServletContextListener listener) {
throw new RuntimeException(
"StartupStatusStub.listenerExecuted() not implemented.");
}
@Override
public boolean allClear() {
throw new RuntimeException(
"StartupStatusStub.allClear() not implemented.");
}
@Override
public boolean isStartupAborted() {
throw new RuntimeException(
"StartupStatusStub.isStartupAborted() not implemented.");
}
@Override
public List<StatusItem> getStatusItems() {
throw new RuntimeException(
"StartupStatusStub.getStatusItems() not implemented.");
}
@Override
public List<StatusItem> getErrorItems() {
throw new RuntimeException(
"StartupStatusStub.getErrorItems() not implemented.");
}
@Override
public List<StatusItem> getWarningItems() {
throw new RuntimeException(
"StartupStatusStub.getWarningItems() not implemented.");
}
@Override
public List<StatusItem> getItemsForListener(ServletContextListener listener) {
throw new RuntimeException(
"StartupStatusStub.getItemsForListener() not implemented.");
}
}

View file

@ -1,123 +0,0 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package stubs.edu.cornell.mannlib.vitro.webapp.utils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.rdf.model.StmtIterator;
import edu.cornell.mannlib.vitro.webapp.utils.NamespaceMapper;
/**
* A minimal implementation of the NamespaceMapper.
*
* I have only implemented the methods that I needed. Feel free to implement
* others.
*/
public class NamespaceMapperStub implements NamespaceMapper {
// ----------------------------------------------------------------------
// Stub infrastructure
// ----------------------------------------------------------------------
private final Map<String, String> prefixMap = new HashMap<String, String>();
public void setPrefixForNamespace(String prefix, String namespace) {
prefixMap.put(prefix, namespace);
}
// ----------------------------------------------------------------------
// Stub methods
// ----------------------------------------------------------------------
@Override
public String getNamespaceForPrefix(String prefix) {
return prefixMap.get(prefix);
}
// ----------------------------------------------------------------------
// Un-implemented methods
// ----------------------------------------------------------------------
@Override
public void addedStatement(Statement arg0) {
throw new RuntimeException(
"NamespaceMapperStub.addedStatement() not implemented.");
}
@Override
public void addedStatements(Statement[] arg0) {
throw new RuntimeException(
"NamespaceMapperStub.addedStatements() not implemented.");
}
@Override
public void addedStatements(List<Statement> arg0) {
throw new RuntimeException(
"NamespaceMapperStub.addedStatements() not implemented.");
}
@Override
public void addedStatements(StmtIterator arg0) {
throw new RuntimeException(
"NamespaceMapperStub.addedStatements() not implemented.");
}
@Override
public void addedStatements(Model arg0) {
throw new RuntimeException(
"NamespaceMapperStub.addedStatements() not implemented.");
}
@Override
public void notifyEvent(Model arg0, Object arg1) {
throw new RuntimeException(
"NamespaceMapperStub.notifyEvent() not implemented.");
}
@Override
public void removedStatement(Statement arg0) {
throw new RuntimeException(
"NamespaceMapperStub.removedStatement() not implemented.");
}
@Override
public void removedStatements(Statement[] arg0) {
throw new RuntimeException(
"NamespaceMapperStub.removedStatements() not implemented.");
}
@Override
public void removedStatements(List<Statement> arg0) {
throw new RuntimeException(
"NamespaceMapperStub.removedStatements() not implemented.");
}
@Override
public void removedStatements(StmtIterator arg0) {
throw new RuntimeException(
"NamespaceMapperStub.removedStatements() not implemented.");
}
@Override
public void removedStatements(Model arg0) {
throw new RuntimeException(
"NamespaceMapperStub.removedStatements() not implemented.");
}
@Override
public String getPrefixForNamespace(String namespace) {
throw new RuntimeException(
"NamespaceMapperStub.getPrefixForNamespace() not implemented.");
}
@Override
public List<String> getPrefixesForNamespace(String namespace) {
throw new RuntimeException(
"NamespaceMapperStub.getPrefixesForNamespace() not implemented.");
}
}

View file

@ -9,6 +9,7 @@
<nav role="navigation"> <nav role="navigation">
<ul id="header-nav" role="list"> <ul id="header-nav" role="list">
<#include "languageSelector.ftl">
<li role="listitem"><a href="${urls.index}" title="index">Index</a></li> <li role="listitem"><a href="${urls.index}" title="index">Index</a></li>
<#if user.loggedIn> <#if user.loggedIn>
<#if user.hasSiteAdminAccess> <#if user.hasSiteAdminAccess>

View file

@ -55,6 +55,9 @@ edu.cornell.mannlib.vitro.webapp.services.shortview.ShortViewServiceSetup
edu.ucsf.vitro.opensocial.OpenSocialSmokeTests edu.ucsf.vitro.opensocial.OpenSocialSmokeTests
# For multiple language support
edu.cornell.mannlib.vitro.webapp.i18n.selection.LocaleSelectionSetup
# The Solr index uses a "public" permission, so the PropertyRestrictionPolicyHelper # The Solr index uses a "public" permission, so the PropertyRestrictionPolicyHelper
# and the PermissionRegistry must already be set up. # and the PermissionRegistry must already be set up.
edu.cornell.mannlib.vitro.webapp.search.solr.SolrSetup edu.cornell.mannlib.vitro.webapp.search.solr.SolrSetup

View file

@ -78,6 +78,16 @@
<url-pattern>/*</url-pattern> <url-pattern>/*</url-pattern>
</filter-mapping> </filter-mapping>
<filter>
<description>Override the Locale in the HttpRequest, if appropriate.</description>
<filter-name>Locale selection filter</filter-name>
<filter-class>edu.cornell.mannlib.vitro.webapp.i18n.selection.LocaleSelectionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Locale selection filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter> <filter>
<filter-name>JSession Strip Filter</filter-name> <filter-name>JSession Strip Filter</filter-name>
<filter-class>edu.cornell.mannlib.vitro.webapp.filters.JSessionStripFilter</filter-class> <filter-class>edu.cornell.mannlib.vitro.webapp.filters.JSessionStripFilter</filter-class>
@ -112,8 +122,8 @@
<filter-mapping> <filter-mapping>
<filter-name>VitroRequestPrep</filter-name> <filter-name>VitroRequestPrep</filter-name>
<url-pattern>/*</url-pattern> <url-pattern>/*</url-pattern>
<dispatcher>request</dispatcher> <dispatcher>REQUEST</dispatcher>
<dispatcher>forward</dispatcher> <dispatcher>FORWARD</dispatcher>
</filter-mapping> </filter-mapping>
<filter> <filter>
@ -123,7 +133,7 @@
<filter-mapping> <filter-mapping>
<filter-name>PageRoutingFilter</filter-name> <filter-name>PageRoutingFilter</filter-name>
<url-pattern>/*</url-pattern> <url-pattern>/*</url-pattern>
<dispatcher>request</dispatcher> <dispatcher>REQUEST</dispatcher>
</filter-mapping> </filter-mapping>
<!-- Spring setup **************************************************** --> <!-- Spring setup **************************************************** -->
@ -154,25 +164,6 @@
--> -->
<!-- Servlets ********************************************************** --> <!-- Servlets ********************************************************** -->
<servlet>
<!--adding only trimSpaces param to defaults to clean up html output-->
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<init-param>
<param-name>fork</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>xpoweredBy</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>trimSpaces</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
<servlet> <servlet>
<servlet-name>IndexController</servlet-name> <servlet-name>IndexController</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.search.controller.IndexController</servlet-class> <servlet-class>edu.cornell.mannlib.vitro.webapp.search.controller.IndexController</servlet-class>
@ -191,15 +182,6 @@
<url-pattern>/RecomputeInferences</url-pattern> <url-pattern>/RecomputeInferences</url-pattern>
</servlet-mapping> </servlet-mapping>
<servlet>
<servlet-name>SDBSetupController</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.freemarker.SDBSetupController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SDBSetupController</servlet-name>
<url-pattern>/sdbsetup</url-pattern>
</servlet-mapping>
<servlet> <servlet>
<servlet-name>MenuManagementEdit</servlet-name> <servlet-name>MenuManagementEdit</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.edit.MenuManagementEdit</servlet-class> <servlet-class>edu.cornell.mannlib.vitro.webapp.controller.edit.MenuManagementEdit</servlet-class>
@ -218,24 +200,6 @@
<url-pattern>/ajax/sparqlQuery</url-pattern> <url-pattern>/ajax/sparqlQuery</url-pattern>
</servlet-mapping> </servlet-mapping>
<!-- This is the new navigation controller. It is not ready for the 1.1 release
see http://issues.library.cornell.edu/browse/NIHVIVO-597
<servlet>
<servlet-name>NavigationController</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.freemarker.NavigationController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>NavigationController</servlet-name>
<url-pattern>/nav/*</url-pattern>
</servlet-mapping>
-->
<servlet>
<servlet-name>fetch</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.QueryServlet</servlet-class>
<!--load-on-startup>2</load-on-startup-->
</servlet>
<servlet> <servlet>
<servlet-name>AboutController</servlet-name> <servlet-name>AboutController</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.freemarker.AboutController</servlet-class> <servlet-class>edu.cornell.mannlib.vitro.webapp.controller.freemarker.AboutController</servlet-class>
@ -370,14 +334,13 @@
<url-pattern>/editRequestDispatch</url-pattern> <url-pattern>/editRequestDispatch</url-pattern>
</servlet-mapping> </servlet-mapping>
<servlet> <servlet>
<servlet-name>FlagUpdateController</servlet-name> <servlet-name>EditRequestAJAX</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.edit.FlagUpdateController</servlet-class> <servlet-class>edu.cornell.mannlib.vitro.webapp.edit.n3editing.controller.EditRequestAJAXController</servlet-class>
</servlet> </servlet>
<servlet-mapping> <servlet-mapping>
<servlet-name>FlagUpdateController</servlet-name> <servlet-name>EditRequestAJAX</servlet-name>
<url-pattern>/flagUpdate</url-pattern> <url-pattern>/editRequestAJAX</url-pattern>
</servlet-mapping> </servlet-mapping>
<servlet> <servlet>
@ -434,24 +397,6 @@
<url-pattern>/jenaXmlFileUpload/*</url-pattern> <url-pattern>/jenaXmlFileUpload/*</url-pattern>
</servlet-mapping> </servlet-mapping>
<servlet>
<servlet-name>OwlImportController</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.owl.OwlImportController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>OwlImportController</servlet-name>
<url-pattern>/owl</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>OwlImportServlet</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.owl.ProtegeOwlImportServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>OwlImportServlet</servlet-name>
<url-pattern>/importOwl</url-pattern>
</servlet-mapping>
<servlet> <servlet>
<servlet-name>JenaAdminServlet</servlet-name> <servlet-name>JenaAdminServlet</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.jena.JenaAdminActions</servlet-class> <servlet-class>edu.cornell.mannlib.vitro.webapp.controller.jena.JenaAdminActions</servlet-class>
@ -551,16 +496,6 @@
<url-pattern>/datapropEdit</url-pattern> <url-pattern>/datapropEdit</url-pattern>
</servlet-mapping> </servlet-mapping>
<servlet>
<servlet-name>KeywordEditController</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.edit.KeywordEditController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>KeywordEditController</servlet-name>
<url-pattern>/keywordEdit</url-pattern>
</servlet-mapping>
<servlet> <servlet>
<servlet-name>OntologyEditController</servlet-name> <servlet-name>OntologyEditController</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.edit.OntologyEditController</servlet-class> <servlet-class>edu.cornell.mannlib.vitro.webapp.controller.edit.OntologyEditController</servlet-class>
@ -759,24 +694,6 @@
<url-pattern>/admin/wait</url-pattern> <url-pattern>/admin/wait</url-pattern>
</servlet-mapping> </servlet-mapping>
<servlet>
<servlet-name>StatementChangeListingController</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.edit.listing.jena.StatementChangeListingController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>StatementChangeListingController</servlet-name>
<url-pattern>/statementHistory</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>WriteOutChangesController</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.edit.listing.jena.WriteOutChangesController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>WriteOutChangesController</servlet-name>
<url-pattern>/writeOutChanges</url-pattern>
</servlet-mapping>
<servlet> <servlet>
<servlet-name>ListVClassWebappsController</servlet-name> <servlet-name>ListVClassWebappsController</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.freemarker.ListVClassWebappsController</servlet-class> <servlet-class>edu.cornell.mannlib.vitro.webapp.controller.freemarker.ListVClassWebappsController</servlet-class>
@ -939,15 +856,6 @@
<url-pattern>/edit/reorder</url-pattern> <url-pattern>/edit/reorder</url-pattern>
</servlet-mapping> </servlet-mapping>
<servlet>
<servlet-name>AdminController</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.AdminController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AdminController</servlet-name>
<url-pattern>/adminCon</url-pattern>
</servlet-mapping>
<servlet> <servlet>
<servlet-name>TermsOfUseController</servlet-name> <servlet-name>TermsOfUseController</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.freemarker.TermsOfUseController</servlet-class> <servlet-class>edu.cornell.mannlib.vitro.webapp.controller.freemarker.TermsOfUseController</servlet-class>
@ -1087,32 +995,6 @@
<url-pattern>/browse</url-pattern> <url-pattern>/browse</url-pattern>
</servlet-mapping> </servlet-mapping>
<servlet>
<servlet-name>pubsbyorg</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.vclass.PubsByDepartmentServlet</servlet-class>
<init-param>
<param-name>workspaceDir</param-name>
<param-value>/usr/local/services/vivo/logs</param-value>
</init-param>
<!--load-on-startup>2</load-on-startup-->
</servlet>
<servlet>
<servlet-name>coauthors</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.vclass.CoAuthorServlet</servlet-class>
<init-param>
<param-name>workspaceDir</param-name>
<param-value>/usr/local/services/vivo/logs</param-value>
</init-param>
<!--load-on-startup>2</load-on-startup-->
</servlet>
<servlet>
<servlet-name>generic_create</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.GenericDBCreate</servlet-class>
<!--load-on-startup>2</load-on-startup-->
</servlet>
<servlet> <servlet>
<servlet-name>serveFiles</servlet-name> <servlet-name>serveFiles</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.filestorage.serving.FileServingServlet</servlet-class> <servlet-class>edu.cornell.mannlib.vitro.webapp.filestorage.serving.FileServingServlet</servlet-class>
@ -1122,21 +1004,6 @@
<url-pattern>/file/*</url-pattern> <url-pattern>/file/*</url-pattern>
</servlet-mapping> </servlet-mapping>
<servlet>
<servlet-name>generic_editprep</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.GenericDBEditPrep</servlet-class>
</servlet>
<servlet>
<servlet-name>generic_update</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.GenericDBUpdate</servlet-class>
</servlet>
<servlet>
<servlet-name>generic_delete</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.GenericDBDelete</servlet-class>
</servlet>
<servlet> <servlet>
<servlet-name>SparqlQuery</servlet-name> <servlet-name>SparqlQuery</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.SparqlQueryServlet</servlet-class> <servlet-class>edu.cornell.mannlib.vitro.webapp.controller.SparqlQueryServlet</servlet-class>
@ -1147,16 +1014,6 @@
<url-pattern>/admin/sparqlquery</url-pattern> <url-pattern>/admin/sparqlquery</url-pattern>
</servlet-mapping> </servlet-mapping>
<servlet>
<servlet-name>VisualizationController</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.visualization.VisualizationController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>VisualizationController</servlet-name>
<url-pattern>/visualization</url-pattern>
</servlet-mapping>
<servlet> <servlet>
<servlet-name>primitiveRdfEdit</servlet-name> <servlet-name>primitiveRdfEdit</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.edit.PrimitiveRdfEdit</servlet-class> <servlet-class>edu.cornell.mannlib.vitro.webapp.controller.edit.PrimitiveRdfEdit</servlet-class>
@ -1176,10 +1033,6 @@
</servlet-mapping> </servlet-mapping>
<!-- ============================== servlet-mappings ======================== --> <!-- ============================== servlet-mappings ======================== -->
<servlet-mapping>
<servlet-name>fetch</servlet-name>
<url-pattern>/fetch</url-pattern>
</servlet-mapping>
<servlet-mapping> <servlet-mapping>
<servlet-name>mailusers</servlet-name> <servlet-name>mailusers</servlet-name>
<url-pattern>/mailusers</url-pattern> <url-pattern>/mailusers</url-pattern>
@ -1238,22 +1091,6 @@
<servlet-name>coauthors</servlet-name> <servlet-name>coauthors</servlet-name>
<url-pattern>/coauthors</url-pattern> <url-pattern>/coauthors</url-pattern>
</servlet-mapping> </servlet-mapping>
<servlet-mapping>
<servlet-name>generic_create</servlet-name>
<url-pattern>/generic_create</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>generic_editprep</servlet-name>
<url-pattern>/generic_editprep</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>generic_update</servlet-name>
<url-pattern>/generic_update</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>generic_delete</servlet-name>
<url-pattern>/generic_delete</url-pattern>
</servlet-mapping>
<!-- ==================== sparql query builder ==================== --> <!-- ==================== sparql query builder ==================== -->
@ -1330,6 +1167,16 @@
<url-pattern>/orng/*</url-pattern> <url-pattern>/orng/*</url-pattern>
</servlet-mapping> </servlet-mapping>
<servlet>
<description>Multiple-language support. Allows user to select his preferred langauge</description>
<servlet-name>LocaleSelectionController</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.i18n.selection.LocaleSelectionController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LocaleSelectionController</servlet-name>
<url-pattern>/selectLocale</url-pattern>
</servlet-mapping>
<!-- ==================== tag libraries ============================== --> <!-- ==================== tag libraries ============================== -->
<jsp-config> <jsp-config>

View file

@ -0,0 +1,70 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
span#toggleContainer {
float:right;
padding:10px 8px 0 0;
font-size: 0.85em;
}
section.property-group {
padding-top: 15px;
border-top:none;
}
section.property-group h2 {
padding: 8px 10px 4px 12px;
}
.scroll-up {
position: absolute;
width: 21px;
height: 30px;
top: 8px; /* changed for redesign, was 0 */
right: 12px; /* changed for redesign, was -21px;*/
}
section.property-group div {
margin-top:15px;
/* display:none; */
}
section.property-group h2 {
font-size: 1.15em !important;
color: #5e6363 !important;
font-weight: normal !important;
background: #fafaf9 !important;
}
ul.propertyTabsList {
margin-left: 4px;
margin-top: 24px
}
ul.propertyTabsList li {
font-size: 1.0em;
}
ul.propertyTabsList li:first-child {
width: 7px;
}
li.nonSelectedGroupTab {
float:left;
border: 1px solid #DFE6E5;
background-color:#E4ECF3;
padding: 6px 8px 6px 8px;
cursor:pointer;
border-top-right-radius: 4px;
-moz-border-radius-topright: 4px;
-webkit-border-top-right-radius: 4px;
border-top-left-radius: 4px;
-moz-border-radius-topleft: 4px;
-webkit-border-top-left-radius: 4px;
}
li.selectedGroupTab {
float:left;
border: 1px solid #DFE6E5;
border-bottom-color:#fff;
background-color:#FFF;
padding: 6px 8px 6px 8px;
border-top-right-radius: 4px;
-moz-border-radius-topright: 4px;
-webkit-border-top-right-radius: 4px;
border-top-left-radius: 4px;
-moz-border-radius-topleft: 4px;
-webkit-border-top-left-radius: 4px;
}
li.groupTabSpacer {
float:left;border-bottom: 1px solid #DFE6E5;background-color:#fff;width:3px;height:37px
}

View file

@ -32,7 +32,7 @@
/* <------ INDIVIDUAL INTRO FOR ANY CLASS*/ /* <------ INDIVIDUAL INTRO FOR ANY CLASS*/
#individual-intro { #individual-intro {
margin-top: 15px; margin-top: 15px;
margin-bottom: 20px; margin-bottom: 0;
position: relative; position: relative;
overflow: hidden; overflow: hidden;
} }
@ -63,7 +63,7 @@ img#uriIcon {
width: 166px; width: 166px;
float: left; float: left;
padding-right: 1.5em; padding-right: 1.5em;
margin-bottom: 20px; margin-bottom: 0;
} }
#share-contact h3 { #share-contact h3 {
margin-top: 15px; margin-top: 15px;
@ -89,7 +89,7 @@ img.individual-photo {
h2#mainImage, #share-contact h2 { h2#mainImage, #share-contact h2 {
font-size: 1em; font-size: 1em;
line-height: 1em; line-height: 1em;
padding-bottom: 0.3em padding-bottom: 0.6em
} }
#photo-wrapper { #photo-wrapper {
position: relative; position: relative;

View file

@ -13,7 +13,6 @@
request.setAttribute("bodyJsp", "/errorbody.jsp"); request.setAttribute("bodyJsp", "/errorbody.jsp");
request.setAttribute("title", "Error"); request.setAttribute("title", "Error");
request.setAttribute("css", ""); request.setAttribute("css", "");
request.setAttribute("appBean", appBean);
request.setAttribute("themeDir", themeDir); request.setAttribute("themeDir", themeDir);
%> %>

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 B

View file

@ -0,0 +1,10 @@
/*!
* Amplify Store - Persistent Client-Side Storage 1.1.0
*
* Copyright 2011 appendTo LLC. (http://appendto.com/team)
* Dual licensed under the MIT or GPL licenses.
* http://appendto.com/open-source-licenses
*
* http://amplifyjs.com
*/
(function(a,b){function e(a,e){c.addType(a,function(f,g,h){var i,j,k,l,m=g,n=(new Date).getTime();if(!f){m={},l=[],k=0;try{f=e.length;while(f=e.key(k++))d.test(f)&&(j=JSON.parse(e.getItem(f)),j.expires&&j.expires<=n?l.push(f):m[f.replace(d,"")]=j.data);while(f=l.pop())e.removeItem(f)}catch(o){}return m}f="__amplify__"+f;if(g===b){i=e.getItem(f),j=i?JSON.parse(i):{expires:-1};if(j.expires&&j.expires<=n)e.removeItem(f);else return j.data}else if(g===null)e.removeItem(f);else{j=JSON.stringify({data:g,expires:h.expires?n+h.expires:null});try{e.setItem(f,j)}catch(o){c[a]();try{e.setItem(f,j)}catch(o){throw c.error()}}}return m})}var c=a.store=function(a,b,d,e){var e=c.type;d&&d.type&&d.type in c.types&&(e=d.type);return c.types[e](a,b,d||{})};c.types={},c.type=null,c.addType=function(a,b){c.type||(c.type=a),c.types[a]=b,c[a]=function(b,d,e){e=e||{},e.type=a;return c(b,d,e)}},c.error=function(){return"amplify.store quota exceeded"};var d=/^__amplify__/;for(var f in{localStorage:1,sessionStorage:1})try{window[f].getItem&&e(f,window[f])}catch(g){}if(window.globalStorage)try{e("globalStorage",window.globalStorage[window.location.hostname]),c.type==="sessionStorage"&&(c.type="globalStorage")}catch(g){}(function(){if(!c.types.localStorage){var a=document.createElement("div"),d="amplify";a.style.display="none",document.getElementsByTagName("head")[0].appendChild(a);try{a.addBehavior("#default#userdata"),a.load(d)}catch(e){a.parentNode.removeChild(a);return}c.addType("userData",function(e,f,g){a.load(d);var h,i,j,k,l,m=f,n=(new Date).getTime();if(!e){m={},l=[],k=0;while(h=a.XMLDocument.documentElement.attributes[k++])i=JSON.parse(h.value),i.expires&&i.expires<=n?l.push(h.name):m[h.name]=i.data;while(e=l.pop())a.removeAttribute(e);a.save(d);return m}e=e.replace(/[^-._0-9A-Za-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u37f-\u1fff\u200c-\u200d\u203f\u2040\u2070-\u218f]/g,"-");if(f===b){h=a.getAttribute(e),i=h?JSON.parse(h):{expires:-1};if(i.expires&&i.expires<=n)a.removeAttribute(e);else return i.data}else f===null?a.removeAttribute(e):(j=a.getAttribute(e),i=JSON.stringify({data:f,expires:g.expires?n+g.expires:null}),a.setAttribute(e,i));try{a.save(d)}catch(o){j===null?a.removeAttribute(e):a.setAttribute(e,j),c.userData();try{a.setAttribute(e,i),a.save(d)}catch(o){j===null?a.removeAttribute(e):a.setAttribute(e,j);throw c.error()}}return m})}})(),function(){function e(a){return a===b?b:JSON.parse(JSON.stringify(a))}var a={},d={};c.addType("memory",function(c,f,g){if(!c)return e(a);if(f===b)return e(a[c]);d[c]&&(clearTimeout(d[c]),delete d[c]);if(f===null){delete a[c];return null}a[c]=f,g.expires&&(d[c]=setTimeout(function(){delete a[c],delete d[c]},g.expires));return f})}()})(this.amplify=this.amplify||{})

View file

@ -1,9 +0,0 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
function validate_upload_file(form_passed){
if (form_passed.datafile.value == "") {
alert ("Please browse and select a photo");
return false;
}
}

View file

@ -2,7 +2,7 @@
$(document).ready(function(){ $(document).ready(function(){
// This function creates and styles the "qTip" tooltip that displays the resource uri and the rdf link when the user clicks the uri/rdf icon. // This function creates and styles the "qTip" tooltip that displays the resource uri and the rdf link when the user clicks the uri/rdf icon.
$('#uriIcon').each(function() $('span#iconControlsLeftSide').children('img#uriIcon').each(function()
{ {
$(this).qtip( $(this).qtip(
{ {
@ -34,6 +34,70 @@ $(document).ready(function(){
}); });
}); });
$('span#iconControlsVitro').children('img#uriIcon').each(function()
{
$(this).qtip(
{
content: {
prerender: true, // We need this for the .click() event listener on 'a.close'
text: '<h5>share the URI for this profile</h5> <input id="uriLink" type="text" value="' + $('#uriIcon').attr('title') + '" /><h5><a class ="rdf-url" href="' + individualRdfUrl + '">view profile in RDF format</a></h5><a class="close" href="#">close</a>'
},
position: {
corner: {
target: 'bottomLeft',
tooltip: 'topLeft'
}
},
show: {
when: {event: 'click'}
},
hide: {
fixed: true, // Make it fixed so it can be hovered over and interacted with
when: {
target: $('a.close'),
event: 'click'
}
},
style: {
padding: '1em',
width: 400,
backgroundColor: '#f1f2ee'
}
});
});
$('span#iconControlsRightSide').children('img#uriIcon').each(function()
{
$(this).qtip(
{
content: {
prerender: true, // We need this for the .click() event listener on 'a.close'
text: '<h5>share the URI for this profile</h5> <input id="uriLink" type="text" value="' + $('#uriIcon').attr('title') + '" /><h5><a class ="rdf-url" href="' + individualRdfUrl + '">view profile in RDF format</a></h5><a class="close" href="#">close</a>'
},
position: {
corner: {
target: 'bottomRight',
tooltip: 'topRight'
}
},
show: {
when: {event: 'click'}
},
hide: {
fixed: true, // Make it fixed so it can be hovered over and interacted with
when: {
target: $('a.close'),
event: 'click'
}
},
style: {
padding: '1em',
width: 400,
backgroundColor: '#f1f2ee'
}
});
});
// Prevent close link for URI qTip from requesting bogus '#' href // Prevent close link for URI qTip from requesting bogus '#' href
$('a.close').click(function() { $('a.close').click(function() {
$('#uriIcon').qtip("hide"); $('#uriIcon').qtip("hide");

View file

@ -0,0 +1,177 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
$(document).ready(function(){
$.extend(this, individualLocalName);
adjustFontSize();
padSectionBottoms();
retrieveLocalStorage();
// ensures that shorter property group sections don't cause the page to "jump around"
// when the tabs are clicked
function padSectionBottoms() {
$.each($('section.property-group'), function() {
var sectionHeight = $(this).height();
if ( sectionHeight < 1000 ) {
$(this).css('margin-bottom', 1000-sectionHeight + "px");
}
});
}
// controls the property group tabs
$.each($('li.clickable'), function() {
var groupName = $(this).attr("groupName");
var $propertyGroupLi = $(this);
$(this).click(function() {
if ( $propertyGroupLi.attr("class") == "nonSelectedGroupTab clickable" ) {
$.each($('li.selectedGroupTab'), function() {
$(this).removeClass("selectedGroupTab clickable");
$(this).addClass("nonSelectedGroupTab clickable");
});
$propertyGroupLi.removeClass("nonSelectedGroupTab clickable");
$propertyGroupLi.addClass("selectedGroupTab clickable");
}
if ( $propertyGroupLi.text() == "View All" ) {
processViewAllTab();
}
else {
padSectionBottoms();
var $visibleSection = $('section.property-group:visible');
$visibleSection.hide();
$('h2[pgroup=tabs]').addClass("hidden");
$('nav#scroller').addClass("hidden");
$('section#' + groupName).show();
}
manageLocalStorage();
return false;
});
});
function processViewAllTab() {
$.each($('section.property-group'), function() {
$(this).css("margin-bottom", "1px");
$(this).children('h2').css("margin-top", "-15px").css("border-bottom","1px solid #DFEBE5").css("padding","12px 25px 10px 20px");
$(this).show();
$('h2[pgroup=tabs]').removeClass("hidden");
$('nav#scroller').removeClass("hidden");
});
}
// Next two functions -- keep track of which property group tab was selected,
// so if we return from a custom form or a related individual, even via the back button,
// the same property group will be selected as before.
function manageLocalStorage() {
var localName = this.individualLocalName;
// is this individual already stored? If not, how many have been stored?
// If the answer is 3, remove the first one in before adding the new one
var current = amplify.store(localName);
var profiles = amplify.store("profiles");
if ( current == undefined ) {
if ( profiles == undefined ) {
var lnArray = [];
lnArray.push(localName);
amplify.store("profiles", lnArray);
}
else if ( profiles != undefined && profiles.length >= 3 ) {
firstItem = profiles[0];
amplify.store(firstItem, null);
profiles.splice(0,1);
profiles.push(localName);
amplify.store("profiles", profiles)
}
else if ( profiles != undefined && profiles.length < 3 ) {
profiles.push(localName);
amplify.store("profiles", profiles)
}
}
var selectedTab = [];
selectedTab.push($('li.selectedGroupTab').attr('groupName'));
amplify.store(localName, selectedTab);
var checkLength = amplify.store(localName);
if ( checkLength.length == 0 ) {
amplify.store(localName, null);
}
}
function retrieveLocalStorage() {
var localName = this.individualLocalName;
var selectedTab = amplify.store(individualLocalName);
if ( selectedTab != undefined ) {
var groupName = selectedTab[0];
// unlikely, but it's possible a tab that was previously selected and stored won't be displayed
// because the object properties would have been deleted (in non-edit mode). So ensure that the tab in local
// storage has been rendered on the page.
if ( $("ul.propertyTabsList li[groupName='" + groupName + "']").length ) {
// if the selected tab is the default first one, don't do anything
if ( $('li.clickable').first().attr("groupName") != groupName ) {
// deselect the default first tab
var $firstTab = $('li.clickable').first();
$firstTab.removeClass("selectedGroupTab clickable");
$firstTab.addClass("nonSelectedGroupTab clickable");
// select the stored tab
$("li[groupName='" + groupName + "']").removeClass("nonSelectedGroupTab clickable");
$("li[groupName='" + groupName + "']").addClass("selectedGroupTab clickable");
// hide the first tab section
$('section.property-group:visible').hide();
if ( groupName == "viewAll" ) {
processViewAllTab();
}
// show the selected tab section
$('section#' + groupName).show();
}
}
}
}
// if there are so many tabs that they wrap to a second line, adjust the font size to
//prevent wrapping
function adjustFontSize() {
var width = 0;
$('ul.propertyTabsList li').each(function() {
width += $(this).outerWidth();
});
if ( width < 922 ) {
var diff = 926-width;
$('ul.propertyTabsList li:last-child').css('width', diff + 'px');
}
else {
var diff = width-926;
if ( diff < 26 ) {
$('ul.propertyTabsList li').css('font-size', "0.96em");
}
else if ( diff > 26 && diff < 50 ) {
$('ul.propertyTabsList li').css('font-size', "0.92em");
}
else if ( diff > 50 && diff < 80 ) {
$('ul.propertyTabsList li').css('font-size', "0.9em");
}
else if ( diff > 80 && diff < 130 ) {
$('ul.propertyTabsList li').css('font-size', "0.84em");
}
else if ( diff > 130 && diff < 175 ) {
$('ul.propertyTabsList li').css('font-size', "0.8em");
}
else if ( diff > 175 && diff < 260 ) {
$('ul.propertyTabsList li').css('font-size', "0.73em");
}
else {
$('ul.propertyTabsList li').css('font-size', "0.7em");
}
// get the new width
var newWidth = 0
$('ul.propertyTabsList li').each(function() {
newWidth += $(this).outerWidth();
});
var newDiff = 926-newWidth;
$('ul.propertyTabsList li:last-child').css('width', newDiff + 'px');
}
}
});

View file

@ -37,9 +37,12 @@
SELECT ?pred ?predLabel ?obj ?objLabel ?graph SELECT ?pred ?predLabel ?obj ?objLabel ?graph
WHERE WHERE
{ {
{ <${entity.URI}> ?pred ?obj
MINUS { GRAPH ?g { <${entity.URI}> ?pred ?obj } } }
UNION
{ GRAPH ?graph { <${entity.URI}> ?pred ?obj} } { GRAPH ?graph { <${entity.URI}> ?pred ?obj} }
OPTIONAL { GRAPH ?h { ?obj rdfs:label ?objLabel } } OPTIONAL { ?obj rdfs:label ?objLabel }
OPTIONAL { GRAPH ?i { ?pred rdfs:label ?predLabel } } OPTIONAL { ?pred rdfs:label ?predLabel }
} ORDER BY ?graph ?pred } ORDER BY ?graph ?pred
limit 10000"/> limit 10000"/>
<form action="admin/sparqlquery" method="get"> <form action="admin/sparqlquery" method="get">
@ -54,9 +57,12 @@
SELECT ?sub ?subL ?pred ?predLabel ?graph SELECT ?sub ?subL ?pred ?predLabel ?graph
WHERE WHERE
{ {
{ ?sub ?pred <${entity.URI}>
MINUS { GRAPH ?g { ?sub ?pred <${entity.URI}> } } }
UNION
{ GRAPH ?graph { ?sub ?pred <${entity.URI}> } } { GRAPH ?graph { ?sub ?pred <${entity.URI}> } }
OPTIONAL { GRAPH ?h { ?sub rdfs:label ?subL } } OPTIONAL { ?sub rdfs:label ?subL }
OPTIONAL { GRAPH ?i { ?pred rdfs:label ?predLabel } } OPTIONAL { ?pred rdfs:label ?predLabel }
} ORDER BY ?graph ?pred } ORDER BY ?graph ?pred
limit 10000"/> limit 10000"/>
<form action="admin/sparqlquery" method="get"> <form action="admin/sparqlquery" method="get">

View file

@ -6,21 +6,22 @@
<#-- Default individual profile page template --> <#-- Default individual profile page template -->
<#--@dumpAll /--> <#--@dumpAll /-->
<section id="individual-intro" class="vcard" role="region"> <section id="individual-intro" class="vcard" role="region">
<#-- Image --> <section id="share-contact" role="region">
<#assign individualImage> <#-- Image -->
<#assign individualImage>
<@p.image individual=individual <@p.image individual=individual
propertyGroups=propertyGroups propertyGroups=propertyGroups
namespaces=namespaces namespaces=namespaces
editable=editable editable=editable
showPlaceholder="with_add_link" /> showPlaceholder="with_add_link" />
</#assign> </#assign>
<#if ( individualImage?contains('<img class="individual-photo"') )>
<#assign infoClass = 'class="withThumb"'/>
</#if>
<div id="photo-wrapper">${individualImage}</div>
<#if ( individualImage?contains('<img class="individual-photo"') )>
<#assign infoClass = 'class="withThumb"'/>
</#if>
<div id="photo-wrapper">${individualImage}</div>
</section>
<!-- start section individual-info -->
<section id="individual-info" ${infoClass!} role="region"> <section id="individual-info" ${infoClass!} role="region">
<#include "individual-adminPanel.ftl"> <#include "individual-adminPanel.ftl">
@ -34,7 +35,8 @@
<@p.label individual editable labelCount /> <@p.label individual editable labelCount />
<#-- Most-specific types --> <#-- Most-specific types -->
<@p.mostSpecificTypes individual /><img id="uriIcon" title="${individual.uri}" class="middle" src="${urls.images}/individual/uriIcon.gif" alt="uri icon"/> <@p.mostSpecificTypes individual />
<span id="iconControlsVitro"><img id="uriIcon" title="${individual.uri}" class="middle" src="${urls.images}/individual/uriIcon.gif" alt="uri icon"/></span>
</h1> </h1>
</#if> </#if>
</header> </header>
@ -48,11 +50,17 @@
<#assign nameForOtherGroup = "other"> <#-- used by both individual-propertyGroupMenu.ftl and individual-properties.ftl --> <#assign nameForOtherGroup = "other"> <#-- used by both individual-propertyGroupMenu.ftl and individual-properties.ftl -->
<#-- Property group menu --> <!-- Property group menu or tabs -->
<#include "individual-propertyGroupMenu.ftl"> <#--
With release 1.6 there are now two types of property group displays: the original property group
menu and the horizontal tab display, which is the default. If you prefer to use the property
group menu, simply substitute the include statement below with the one that appears after this
comment section.
<#-- Ontology properties --> <#include "individual-property-group-menus.ftl">
<#include "individual-properties.ftl"> -->
<#include "individual-property-group-tabs.ftl">
<#assign rdfUrl = individual.rdfUrl> <#assign rdfUrl = individual.rdfUrl>

View file

@ -6,7 +6,7 @@
<#if individual.showAdminPanel> <#if individual.showAdminPanel>
<section id="admin"> <section id="admin">
<h3>Admin Panel</h3><a class="edit-individual" href="${individual.controlPanelUrl()}" title="edit this individual">Edit this individual</a> <h3 id="adminPanel">Admin Panel</h3><a class="edit-individual" href="${individual.controlPanelUrl()}" title="edit this individual">Edit this individual</a>
<section id = "verbose-mode"> <section id = "verbose-mode">
<#if verbosePropertySwitch?has_content> <#if verbosePropertySwitch?has_content>

View file

@ -2,29 +2,6 @@
<#-- Template for property listing on individual profile page --> <#-- Template for property listing on individual profile page -->
<#import "lib-properties.ftl" as p>
<#assign subjectUri = individual.controlPanelUrl()?split("=") >
<#list propertyGroups.all as group>
<#assign groupName = group.getName(nameForOtherGroup)>
<#assign verbose = (verbosePropertySwitch.currentValue)!false>
<section class="property-group" role="region">
<nav class="scroll-up" role="navigation">
<a href="#branding" title="scroll up">
<img src="${urls.images}/individual/scroll-up.gif" alt="scroll to property group menus" />
</a>
</nav>
<#-- Display the group heading -->
<#if groupName?has_content>
<#--the function replaces spaces in the name with underscores, also called for the property group menu-->
<#assign groupNameHtmlId = p.createPropertyGroupHtmlId(groupName) >
<h2 id="${groupNameHtmlId}">${groupName?capitalize}</h2>
<#else>
<h2 id="properties">Properties</h2>
</#if>
<#-- List the properties in the group -->
<#list group.properties as property> <#list group.properties as property>
<article class="property" role="article"> <article class="property" role="article">
<#-- Property display name --> <#-- Property display name -->
@ -35,17 +12,17 @@
</a> </a>
</h3> </h3>
<#elseif property.localName == "hasResearcherRole" && editable > <#elseif property.localName == "hasResearcherRole" && editable >
<h3 id="${property.localName}">${property.name} <@p.addLink property editable /> <@p.verboseDisplay property /> <h3 id="${property.localName}">${property.name} <@p.addLink property editable /> <@p.verboseDisplay property />
<a id="manageGrantLink" class="manageLinks" href="${urls.base}/manageGrants?subjectUri=${subjectUri[1]!}" title="manage grants & projects" <#if verbose>style="padding-top:10px"</#if> > <a id="manageGrantLink" class="manageLinks" href="${urls.base}/manageGrants?subjectUri=${subjectUri[1]!}" title="manage grants & projects" <#if verbose>style="padding-top:10px"</#if> >
manage grants & projects manage grants & projects
</a> </a>
</h3> </h3>
<#elseif property.localName == "organizationForPosition" && editable > <#elseif property.localName == "organizationForPosition" && editable >
<h3 id="${property.localName}">${property.name} <@p.addLink property editable /> <@p.verboseDisplay property /> <h3 id="${property.localName}">${property.name} <@p.addLink property editable /> <@p.verboseDisplay property />
<a id="managePeopleLink" class="manageLinks" href="${urls.base}/managePeople?subjectUri=${subjectUri[1]!}" title="manage people" <#if verbose>style="padding-top:10px"</#if> > <a id="managePeopleLink" class="manageLinks" href="${urls.base}/managePeople?subjectUri=${subjectUri[1]!}" title="manage people" <#if verbose>style="padding-top:10px"</#if> >
manage affiliated people manage affiliated people
</a> </a>
</h3> </h3>
<#else> <#else>
<h3 id="${property.localName}">${property.name} <@p.addLink property editable /> <@p.verboseDisplay property /> </h3> <h3 id="${property.localName}">${property.name} <@p.addLink property editable /> <@p.verboseDisplay property /> </h3>
</#if> </#if>
@ -61,5 +38,3 @@
</ul> </ul>
</article> <!-- end property --> </article> <!-- end property -->
</#list> </#list>
</section> <!-- end property-group -->
</#list>

View file

@ -0,0 +1,53 @@
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
<#-- Template for property listing on individual profile page -->
<#import "lib-properties.ftl" as p>
<#assign subjectUri = individual.controlPanelUrl()?split("=") >
<#assign nameForOtherGroup = nameForOtherGroup!"other">
<#if (propertyGroups.all)??>
<#assign groups = propertyGroups.all>
<#if groups?has_content>
<#if (groups?size > 1) || (groups?first).getName(nameForOtherGroup)?has_content>
<nav id="property-group-menu" role="navigation">
<ul role="list">
<#list groups as group>
<#assign groupname = group.getName(nameForOtherGroup)>
<#if groupname?has_content>
<#--create property group html id is the function that will replace all spaces with underscore to make a valid id-->
<#assign groupnameHtmlId = p.createPropertyGroupHtmlId(groupname) >
<#-- capitalize will capitalize each word in the name; cap_first only the first. We may need a custom
function to capitalize all except function words. -->
<li role="listitem"><a href="#${groupnameHtmlId}" title="group name">${groupname?capitalize}</a></li>
</#if>
</#list>
</ul>
</nav>
</#if>
</#if>
</#if>
<#list propertyGroups.all as group>
<#assign groupName = group.getName(nameForOtherGroup)>
<#assign verbose = (verbosePropertySwitch.currentValue)!false>
<section class="property-group" role="region">
<nav class="scroll-up" role="navigation">
<a href="#branding" title="scroll up">
<img src="${urls.images}/individual/scroll-up.gif" alt="scroll to property group menus" />
</a>
</nav>
<#-- Display the group heading -->
<#if groupName?has_content>
<#--the function replaces spaces in the name with underscores, also called for the property group menu-->
<#assign groupNameHtmlId = p.createPropertyGroupHtmlId(groupName) >
<h2 id="${groupNameHtmlId}">${groupName?capitalize}</h2>
<#else>
<h2 id="properties">Properties</h2>
</#if>
<#-- List the properties in the group -->
<#include "individual-properties.ftl">
</section> <!-- end property-group -->
</#list>

Some files were not shown because too many files have changed in this diff Show more