How to retrieve dynamic content from database? - content-management-system

I'm evaluating java-based cms and selecting one as our cms ,now I'm learning dotcms , I need to know how to retrieve content from db like traditional jsp/bo does,I'm new to dotcms, the official documents only tell how to add static content but dynamic content , say running a sql and getting the wanted data ,then putting them into pages. We are doing an internal website where employees can browse news, events, colleagues information etc which managed through a cms, the information is definitely dynamic and updated regularly. We plan to use spring mvc on the project. Any ideas on the question?
thank you.

To get this to work you need to do a few things:
If you want to use a different database, then you can add a new resource to the conf/Catalina/localhost/ROOT.xml file. If you want to use the dotCMS database to host the additional tables then you can skip this step.
From within your java code you can get a database connection using the DbConnectionFactory class. Now you can read the data from the database. Here's an example:
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
Connection conn = DbConnectionFactory.getConnection();
Statement selectStatement;
try {
selectStatement = conn.createStatement();
try {
selectStatement.execute("SELECT * FROM your_table WHERE your_where_clause etc...");
ResultSet result = selectStatement.getResultSet();
if (result.next()) {
.. do your stuff here...
// for example:
// Long dbId = result.getLong("Id");
// String stringField = result.getString("stringFieldName");
// int intField = result.getInt("intFieldName");
} finally {
selectStatement.close();
}
} catch (SQLException e1) {
// Log the error here
}
}
If you want to use this data in velocity you'll need to create a viewtool. Read more about that here: http://dotcms.com/docs/latest/DynamicPluginsViewtool

Related

Trying to add Support For Index Usage on EFCore Spanner Provider

I'm writing a driver for EF Core for Spanner - In basic level it works and I can write Read and Write Queries that get's translated to Spanner SQL , executed and return results etc..
Now I'm trying to add Support For Read Query with Secondary Index.
Ultimately I'm trying to generate this SQL Query:
SELECT * FROM PostTags#{ FORCE_INDEX = PostTagsByTagId } WHERE TagId = 1
From This Linq:
var postTag = ctx.PostTags.WithIndex("PostTagsByTagId").Where(x => x.TagId == 1).FirstOrDefault();
I've added extension method as follow:
public static class SpannerIndexSupport
{
public static IQueryable<TSource> WithIndex<TSource>(this IQueryable<TSource> query, string indexName)
{
var methodDefinition = typeof(SpannerIndexSupport).GetTypeInfo().GetMethods().Single(m => m.Name == "WithIndex");
var method = methodDefinition.MakeGenericMethod(typeof(TSource));
var args = new[] { query.Expression, Expression.Constant(indexName) };
var expression = Expression.Call(null, method, args);
return query.Provider.CreateQuery<TSource>(expression);
}
}
And tried to write IAsyncQueryProvider to support it but couldn't find a way to make it work.
Any ideas Anyone?
In the official Spanner EFCore library (https://github.com/GoogleCloudPlatform/google-cloud-dotnet/tree/master/apis/Google.Cloud.EntityFrameworkCore.Spanner/Google.Cloud.EntityFrameworkCore.Spanner), I would start by overriding VisitTable(TableExpression tableExpression) in SpannerQuerySqlGenerator:
https://github.com/GoogleCloudPlatform/google-cloud-dotnet/tree/master/apis/Google.Cloud.EntityFrameworkCore.Spanner/Google.Cloud.EntityFrameworkCore.Spanner/Query/Sql/Internal/SpannerQuerySqlGenerator.cs
This will allow you to get a proof of concept going because you can directly influence the generated SQL text there.
Once that works, then you will want to make it proper.
I suppose there might be a few ways to make this work. The simplest might be to have some custom no-op method marker in the Linq expression tree and then register an IMethodCallTranslator to convert it either to a custom spanner specific Expression (whose Accept calls into SqlGenerator to generate the proper Sql) or possibly creating a SqlTranslatingExpressionVisitor to switch out the table expression to a custom one that allows the FORCE_INDEX.
Sorry I couldn't help more.
This is now supported in the official Entity Framework provider for Google Cloud Spanner. You can add this by adding a tag to the query like this:
var singersOrderedByFullName = context.Singers
// This will add the following comment to the generated query:
// `-- Use hint: force_index FullName`
// This comment will be picked up by the interceptor and an index
// hint will be added to the query that is executed.
.TagWith("Use hint: force_index FullName")
.OrderBy(s => s.FullName)
.AsAsyncEnumerable();
A full example can be found here: https://github.com/googleapis/dotnet-spanner-entity-framework/blob/main/Google.Cloud.EntityFrameworkCore.Spanner.Samples/Snippets/QueryHintSample.cs

What steps are required to add support for Phoenix to ActiveJDBC?

I am trying to add some support for Apache Phoenix to ActiveJDBC. I am using the ActiveJDBC simple-example project as test, and making changes to a clone of ActiveJDBC 2.0-SNAPSHOT (latest from github).
So far in ActiveJDBC 2.0-SNAPSHOT I have:
created a PhoenixDialect class in org.javalite.activejdbc.dialects to
Override the insert method (Phoenix uses UPSERT)
added an if stanza to the getDialect(String dbType) method in
Configuration
In the simple-example project I have:
added the phoenix-client as a dependency (we are using Phoenix as
part of HortonWorks HDP 2.5.3.0 on HBase 1.1.2.2.5)
set the database.properties with Phoenix values
created the relevant tables in Phoenix manually (db-migrate does
not work for obvious reasons)
However, the database dialect is not being recognized, and is, I believe, defaulting to the DefaultDialect as I get a Phoenix error on the use of "INSERT" which is not recognized in the Phoenix grammar. Phoenix grammar
Are there additional steps I am missing when adding support for an additional dialect?
I also suspect the Phoenix jdbc driver may not support a getDbName() type method, the Phoenix driver, when asked for getPropertyInfo() returns EMPTY_INFO, see PhoenixEmbeddedDriver
If the driver does not return the DbName, is there a workaround?
It might be worth mentioning we are successfully interacting with Phoenix using standard Java jdbc classes (PreparedStatement and all that good stuff), but ActiveJDBC is much more elegant and we would like to use it.
Pieces of what we have so far:
PhoenixDialect
import java.util.Iterator;
import java.util.Map;
import org.javalite.activejdbc.MetaModel;
import static org.javalite.common.Util.join;
public class PhoenixDialect extends DefaultDialect {
#Override
public String insert(MetaModel metaModel, Map<String, Object> attributes) {
StringBuilder query = new StringBuilder().append("UPSERT INTO ").append(metaModel.getTableName()).append(' ');
if (attributes.isEmpty()) {
appendEmptyRow(metaModel, query);
} else {
boolean addIdGeneratorCode = (metaModel.getIdGeneratorCode() != null
&& attributes.get(metaModel.getIdName()) == null); // do not use containsKey
query.append('(');
if (addIdGeneratorCode) {
query.append(metaModel.getIdName()).append(", ");
}
join(query, attributes.keySet(), ", ");
query.append(") VALUES (");
if (addIdGeneratorCode) {
query.append(metaModel.getIdGeneratorCode()).append(", ");
}
Iterator<Object> it = attributes.values().iterator();
appendValue(query, it.next());
while (it.hasNext()) {
query.append(", ");
appendValue(query, it.next());
}
query.append(')');
}
return query.toString();
}
}
Configuration
public Dialect getDialect(String dbType) {
Dialect dialect = dialects.get(dbType);
if (dialect == null) {
if (dbType.equalsIgnoreCase("Oracle")) {
dialect = new OracleDialect();
}
else if (dbType.equalsIgnoreCase("Phoenix")) {
dialect = new PhoenixDialect();
}
else if (dbType.equalsIgnoreCase("MySQL")) {
dialect = new MySQLDialect();
}
database.properties
development.driver=org.apache.phoenix.jdbc.PhoenixDriver
development.username=anything
development.password=anything
development.url=jdbc:phoenix:hdp-c21:2181:/hbase-unsecure
Here is a branch that was used to integrate SQLServer with new Dialect, test suite and other related stuff:
https://github.com/javalite/activejdbc/tree/sql_server_integration
Here is a branch for h2:
https://github.com/javalite/activejdbc/commits/h2integration
Things may have changed since then, but this branch will give you good guidance. Best if you fork the project, and when done submit your work as a pull request.

Generating password protected pdf. How to get unique password for every user?

I've uploaded my reports on JasperServer where I'm scheduling the reports and send the pdf as attachments in emails to the users using the jobs rest api. Everything works perfectly, however we also need the pdf's to be encrypted. I've read the wiki topic and was able to encrypt the pdf.
But we want the passwords to be dynamic and be different for every user(for exmaple some combination of their phone numbers and date of births). The example described in the link specifies the password as a report property in the jrxml.
<property name="net.sf.jasperreports.export.pdf.user.password" value="123456"/>
<property name="net.sf.jasperreports.export.pdf.owner.password" value="123456"/>
The password is specified as a string and is similar for every pdf generated from this jrxml.
I tried something like this
<property name="net.sf.jasperreports.export.pdf.user.password" value="{$F{dateOfBirth}}"/>
where $F{dateOfBirth} is the dateOfBirth of the user for which the query is being run. But instead of putting in the field value, it just considers it a string and sets the password to="{$F{dateOfBirth}}"
How do I go along with this? Is their any way for me to set different passwords for every user?
NOTE:The datasource is configured for the report on the jasperserver. On the job execution api call, Jasperserver executed the query, fills the report, exports as pdf and sends it as email to the user.
Add the following code in your Java code.
JasperPrint print = JasperFillManager.fillReport(jasper, parameters, beanColDataSource2);
print.setProperty("net.sf.jasperreports.export.pdf.user.password", "jasper123");
Add in JRXML.
property name="net.sf.jasperreports.export.pdf.encrypted" value="True"
property name="net.sf.jasperreports.export.pdf.128.bit.key" value="True"
property name="net.sf.jasperreports.export.pdf.permissions.allowed" value="PRINTING"
As one comment mentioned, just use Java.
Here is an example, how I would code this (it's not perfect, but I think you will get it):
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import net.sf.jasperreports.engine.JRDefaultScriptlet;
import net.sf.jasperreports.engine.JRScriptletException;
import net.sf.jasperreports.engine.fill.JRFillParameter;
public class GetBirthdayScriptlet extends JRDefaultScriptlet {
private Connection conn;
private Connection getConnection() throws JRScriptletException {
if (conn == null) {
if (getParameterValue(JRFillParameter.REPORT_CONNECTION) != null) {
conn = (Connection) (getParameterValue(JRFillParameter.REPORT_CONNECTION));
} else {
throw new RuntimeException("No db-connection configured in the report!");
}
}
return conn;
}
public String getBirthday(String email) throws JRScriptletException, SQLException {
ResultSet result = null;
String resultString = null;
CallableStatement stmt = getConnection().prepareCall("select birthday from birthday_table where email = " + email);
stmt.executeUpdate();
result = stmt.getResultSet();
if(result.next()){
result.getString(1);
}
return resultString;
}
}
Pack this little snippet into a jar and add it to your Studio Build Path and also upload it to your Jaspersoft Server.
In your report outline rightlick on Scriptlets -> "Create Scriptlet"
The class of the scriptlet is GetBirthdayScriptlet (this is the codesnippet-class).
The expression you want to use in your report is:
$P{>>scriptlet-name<<_SCRIPTLET}.getBirthday("email#example.com")
Instead of entering the String, just use the parameter.
Also, maybe think of using the Jaspersoft Built In Parameter LoggedInUserEmailAddress
This helps if you want live-reports to be encrypted.

List all tables in an mdb file

Is there any way to list the names of all of the tables in an MDB file? I am attempting to create a program that tests the user on Quizbowl questions. I would like to organize the questions and answers so that each question set is located within its own table. Simply put, I am unfamiliar with the API for Jackcess - I have tried searching to see if there is a method that would do this, but have failed.
Thank you.
Simply use the .getTableNames() method of the Database object, like this:
import java.io.File;
import com.healthmarketscience.jackcess.Database;
// ...
String dbFileSpec = "C:/Users/Public/mdbTest.mdb";
try (Database db = DatabaseBuilder.open(new File(dbFileSpec))) {
for (String tableName : db.getTableNames()) {
System.out.println(tableName);
}
} catch (Exception e) {
e.printStackTrace(System.err);
}

MSTest with Moq - DAL setup

I'm new to Moq, and just started on a project that's already in development. I'm responsible for setting up unit testing. There's a custom class for the DatabaseFactory that uses EnterpriseLibrary and looks like this:
public Database CreateCommonDatabase()
{
return CreateDatabaseInstance(string.Empty);
}
private static Database CreateDatabaseInstance(string foo)
{
var database = clientCode == string.Empty
? DatabaseFactory.CreateDatabase("COMMON")
: new OracleDatabase(new ClientConnections().GetConnectionString(foo)));
return database;
}
Now, here's where that gets used (ResultData is another class of the type DataSet):
public ResultData GetNotifications(string foo, string foo2, Database database)
{
var errMsg = string.Empty;
var retval = 0;
var ds = new DataSet();
var sqlClause =
#"[Some SELECT statement here that uses foo]";
DbCommand cm = database.GetSqlStringCommand(sqlClause);
cm.CommandType = CommandType.Text;
// Add Parameters
if (userSeq != string.Empty)
{
database.AddInParameter(cm, ":foo2", DbType.String, foo2);
}
try
{
ds = database.ExecuteDataSet(cm);
}
catch (Exception ex)
{
retval = -99;
errMsg = ex.Message;
}
return new ResultData(ds, retval, errMsg);
}
Now, originally, the Database wasn't passed in as a parameter, but the method was creating a new instance of the DatabaseFactory using the CreateCommonDatabase method, and using it from there. However, that leaves the class untestable because I can't keep it from actually hitting the database. So, I went with Dependency Injection, and pass the Database in.
Now, I'm stuck, because there's no way to mock Database in order to test GetNotifications. I'm wondering if I'm overly complicating things, or if I'm missing something. Am I doing this the right way, or should I be rethinking how I've got this set up?
Edit to add more info*****
I really don't want to test the database. I want the Data.Notifications class (above) to return an instance of ResultData, but that's all I really want to test. If I go a level up, to the Business layer, I have this:
public DataSet GetNotifications(string foo, string foo1, out int returnValue, out string errorMessage, Database database)
{
ResultData rd = new data.Notifications().GetNotifications(foo, foo1, database);
returnValue = rd.ResultValue;
errorMessage = rd.ErrorMessage;
return rd.DataReturned;
}
So, originally, the database wasn't passed in, it was the Data.Notifications class that created it - but then again, if I left it that way, I couldn't help but hit the database to test this Business layer object. I modified all of the code to pass the Database in (which gets created a the web's Base page), but now I'm just not certain what to do next. I thought I was one unit test away from having this resolved, but apparently, either I'm wrong or I've got a mental roadblock to the right path.
You should be able to create a mock Database object if the methods in it are virtual. If they are not, then you have a little bit of a problem.
I don't know what type "Database" is, but you have a few options.
If you own the source code to Database, I would recommend extracting an interface IDatabase, rather than dealing with a Database class type. This will eliminate some complexity and give you something extremely testable.
If you don't have access to the Database class, you can always solve this with another layer of abstraction. Many people in this case use a Repository pattern that wraps the data access layer. Generally speaking in this case, most people leave testing Respository classes to integration tests (tests without any isolation), rather than unit tests.
Here's how you'd setup your test using option #1:
[TestMethod]
public void GetNotifications_PassedNullFoo_ReturnsData()
{
//Arrange
Mock<IDatabase> mockDB = new Mock<IDatabase>();
mockDB.Setup(db => db.ExecuteDataSet()).Returns(new DataSet() ... );
//Act
FooClass target = new fooClass();
var result = target.GetNotifications(null, "Foo2", mockDB.Object);
//Assert
Assert.IsTrue(result.DataSet.Rows.Count > 0);
}
My dataset code is a little rusty, but hopefully this gives you the general idea.
Based on the code you've given, I would think you would want to talk to the database, and not a mocked version.
The reason is that your GetNotifications code contains DB-specific instructions, and you'll want those to pass validation at the DB Engine level. So just pass in a Database that is connected to your test DB instance.
If you took the testing abstraction to a higher level, where you built unit tests for the database call and a version of this test that used a mocked database, you'd still have to run integration tests, which ends up being triple the work for the same amount of code coverage. In my opinion, it's far more efficient to do an integration test at tier borders you control then to write unit tests for both sides of the contract and integration tests.