I am trying to create an IndexWriter and write to a Lucene Index. Here is my code:
public class Indexer {
public static Analyzer _analyzer = new StandardAnalyzer(Lucene.Net.Util.LuceneVersion.LUCENE_48);
private void WriteToIndex() {
var config = new IndexWriterConfig(Lucene.Net.Util.LuceneVersion.LUCENE_48, _analyzer).SetUseCompoundFile(false);
using (IndexWriter indexWriter = new IndexWriter(LuceneDirectory, config)) <-- This throws an error!
{
// ....
}
}
}
But I keep getting an exception when trying to create the IndexWriter:
Exception thrown: 'Lucene.Net.Util.SetOnce`1.AlreadySetException' in Lucene.Net.dll
Additional information: The object cannot be set twice!
What am I doing wrong? The code compiles perfectly. I'm using Lucene.NET, but I'm guessing it should apply to Java too.
You are getting this exception because you are reusing an IndexWriterConfig, which is not intended to be shared between IndexWriter instances. Generate a new IndexWriterConfig instead, and it should work fine.
Related
I am working on a legacy non-Spring application, and it is being migrated from Hibernate 3 to Hibernate 5.6.0.Final (latest at this time). I have generally never used Hibernate Event Listeners in my work, so this is quite new to me, and I am studying these in Hibernate 5.
Currently in some test class we have defined the code this way for Hibernate 3:
protected static Configuration createSecuredDatabaseConfig() {
Configuration config = createUnrestrictedDatabaseConfig();
config.setListener("pre-insert", "com.app.server.services.db.eventlisteners.MySecurityHibernateEventListener");
config.setListener("pre-update", "com.app.server.services.db.eventlisteners.MySecurityHibernateEventListener");
config.setListener("pre-delete", "com.app.server.services.db.eventlisteners.MySecurityHibernateEventListener");
config.setListener("pre-load", "com.app.server.services.db.eventlisteners.EkoSecurityHibernateEventListener");
return config;
}
This is obviously no longer valid, and I believe I need to create a Hibernate Integrator, which I have done.
public class MyEventListenerIntegrator implements Integrator {
#Override
public void integrate(Metadata metadata, SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
EventListenerRegistry eventListenerRegistry = serviceRegistry.getService(EventListenerRegistry.class);
eventListenerRegistry.getEventListenerGroup(EventType.PRE_INSERT).appendListener(new MySecurityHibernateEventListener());
eventListenerRegistry.getEventListenerGroup(EventType.PRE_UPDATE).appendListener(new MySecurityHibernateEventListener());
eventListenerRegistry.getEventListenerGroup(EventType.PRE_DELETE).appendListener(new MySecurityHibernateEventListener());
eventListenerRegistry.getEventListenerGroup(EventType.PRE_LOAD).appendListener(new MySecurityHibernateEventListener());
}
So, now I believe the next step is to add this to the session via the registry builder. I am using this website to help me:
https://www.boraji.com/hibernate-5-event-listener-example
Because we were using older Hibernate 3, we had code to create our session factory as follows:
protected static SessionFactory buildSessionFactory(Database db)
{
if (db == null) {
throw new NullPointerException("Database specifier cannot be null");
}
try {
Configuration config = createSessionFactoryConfiguration(db);
String url = config.getProperty("connection.url");
String user = config.getProperty("connection.username");
String password = config.getProperty("connection.password");
try {
String dbDriver = config.getProperty("hibernate.connection.driver_class");
Class.forName(dbDriver);
Connection conn = DriverManager.getConnection(url, user, password);
}
catch (SQLException error) {
logger.info("Didn't find driver, on QA or production, so it's okay to assume we have DB connection");
error.printStackTrace();
}
SessionFactory sessionFactory = config.buildSessionFactory();
sessionFactoryConfigs.put(sessionFactory, config); // Cannot recover config from factory instance, must be stored.
return sessionFactory;
}
catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
logger.error("Initial SessionFactory creation failed.", ex);
throw new ExceptionInInitializerError(ex);
}
}
The link that I referred to above has a much different way of creating the sessionfactory. So, I'll be testing that out to see if it works in our app.
Without Spring handling our sessions and transactions, in this app it is coded by hand the way it was done before Spring, and I haven't seen that kind of code in years.
I solved this issue with the help from the link I provided above. However, I didn't copy exactly what they did, but some of it helped. My solution is as follows:
protected static SessionFactory createSecuredDatabaseConfig() {
Configuration config = createUnrestrictedDatabaseConfig();
BootstrapServiceRegistry bootstrapRegistry =
new BootstrapServiceRegistryBuilder()
.applyIntegrator(new EkoEventListenerIntegrator())
.build();
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder(bootstrapRegistry).applySettings(config.getProperties()).build();
SessionFactory sessionFactory = config.buildSessionFactory(serviceRegistry);
return sessionFactory;
}
This was it. I tried multiple different ways to register the events without the BootstrapServiceRegistry, but none of those worked. I did have to create the integrator. What I did NOT include was the following:
MetadataSources sources = new MetadataSources(serviceRegistry )
.addPackage("com.myproject.server.model");
Metadata metadata = sources.getMetadataBuilder().build();
// did not create the sessionFactory this way
sessionFactory = metadata.getSessionFactoryBuilder().build();
If I had gone further and use this method to create the sessionFactory, then all of my queries would have been complaining about not being able to find the parameterName, which is something else.
The Hibernate Integrator and this method to create the sessionFactory is all for the unit tests. Without registering these events, one unit test would fail, and now it doesn't. So, this solves my problem for now.
OLD TITLE: iTextSharp convert HTML to PDF "The document has no pages."
I am using iTextSharp and xmlworker to convert html from a view to PDF in ASP.NET Core 2.1
I tried many code snippets I found online but all generate an exception:
The document has no pages.
Here is my current code:
public static byte[] ToPdf(string html)
{
byte[] output;
using (var document = new Document())
{
using (var workStream = new MemoryStream())
{
PdfWriter writer = PdfWriter.GetInstance(document, workStream);
writer.CloseStream = false;
document.Open();
using (var reader = new StringReader(html))
{
XMLWorkerHelper.GetInstance().ParseXHtml(writer, document, reader);
document.Close();
output = workStream.ToArray();
}
}
}
return output;
}
UPDATE 1
Thanks to #Bruno Lowagie's advice, I upgraded to iText7 and pdfHTML, but I can't find much tutorials about it.
I tried this code:
public static byte[] ToPdf(string html)
{
html = "<html><head><title>Extremely Basic Title</title></head><body>Extremely Basic Content</body></html>";
byte[] output;
using (var workStream = new MemoryStream())
using (var pdfWriter = new PdfWriter(workStream))
{
using (var document = HtmlConverter.ConvertToDocument(html, pdfWriter))
{
//Passes the document to a delegated function to perform some content, margin or page size manipulation
//pdfModifier(document);
}
//Returns the written-to MemoryStream containing the PDF.
return workStream.ToArray();
}
}
but I get
System.NullReferenceException
when I call HtmlConverter.ConvertToDocument(html, pdfWriter)
Am I missing something?
UPDATE 2
I tried to debug using source code.
This is the stack trace
System.NullReferenceException
HResult=0x80004003
Message=Object reference not set to an instance of an object.
Source=itext.io
StackTrace: at iText.IO.Font.FontCache..cctor() in S:\Progetti\*****\itext7-dotnet-develop\itext\itext.io\itext\io\font\FontCache.cs:line 76
This is the code that generates the exception:
static FontCache()
{
try
{
LoadRegistry();
foreach (String font in registryNames.Get(FONTS_PROP))
{
allCidFonts.Put(font, ReadFontProperties(font));
}
}
catch (Exception) { }
}
registryNames count = 0 and .Get(FONTS_PROP) throws the exception
UPDATE 3
The problem was related to some sort of cache. I can't really understand what, but as you can see in the code the exception was generated when it tried to load fonts from cache.
I realized that, after having tried the same code on a new project where it worked.
So I cleaned the solution, deleted bin, obj, .vs, killed IIS Express, removed and reinstalled all nuget packages then run again, magically it worked.
Then I had to make only one fix to the code:
Instead of HtmlConverter.ConvertToDocument that generates only a 15 bytes document I used HtmlConverter.ConvertToPdf to generate a full PDF.
Here is the complete code:
public static byte[] ToPdf(string html)
{
using (var workStream = new MemoryStream())
{
using (var pdfWriter = new PdfWriter(workStream))
{
HtmlConverter.ConvertToPdf(html, pdfWriter);
return workStream.ToArray();
}
}
}
I had this EXACT same problem, and after digging down all the way to iText7's FontCache object and getting an error when trying to create my OWN FontProgram to use from a raw TTF file (which also failed with the same null reference error), I finally "solved" my problem.
Apparently iText has some internal errors/exceptions that they are just sort of "skipping" and "pushing past", because I realized by accident that I had "Enable Just My Code" in Visual Studios disabled, and so my system was trying to debug iText7's code as well as mine. The moment that I re-enabled it in my Visual Studio settings (Tools > Options > Debugging > General > Enable Just My Code checkbox), the problem magically went away.
So I spent four hours trying to troubleshoot a problem that was in THEIR code, but that they apparently found some way to work around and push through the method anyways even on a null reference failure.
My convert to PDF function is now working just fine.
I was getting this error as well, but noticed it was only on the first attempted load of the SvgConverter. So I added this at the top of my class, and it seems to have fixed hidden the bug.
using iText.Kernel.Pdf;
using iText.IO.Font;
public class PdfBuilder {
static PdfBuilder() {
try {
FontCache.GetRegistryNames();
}
catch(Exception) {
// ignored... this forces the FontCache to initialize
}
}
...
}
I was using itext 7 everything works fine in Console application.
When I use same code in Web/Function App project, I started getting below error.
System.NullReferenceException
HResult=0x80004003
Message=Object reference not set to an instance of an object.
Source=itext.html2pdf
StackTrace:
at iText.Html2pdf.Attach.Impl.Tags.BrTagWorker..ctor(IElementNode element, ProcessorContext context)
at iText.Html2pdf.Attach.Impl.DefaultTagWorkerMapping.<>c.<.cctor>b__1_10(IElementNode lhs, ProcessorContext rhs)
at iText.Html2pdf.Attach.Impl.DefaultHtmlProcessor.Visit(INode node)
at iText.Html2pdf.Attach.Impl.DefaultHtmlProcessor.Visit(INode node)
at iText.Html2pdf.Attach.Impl.DefaultHtmlProcessor.Visit(INode node)
at iText.Html2pdf.Attach.Impl.DefaultHtmlProcessor.Visit(INode node)
at iText.Html2pdf.Attach.Impl.DefaultHtmlProcessor.Visit(INode node)
at iText.Html2pdf.Attach.Impl.DefaultHtmlProcessor.Visit(INode node)
at iText.Html2pdf.Attach.Impl.DefaultHtmlProcessor.Visit(INode node)
at iText.Html2pdf.Attach.Impl.DefaultHtmlProcessor.ProcessDocument(INode root, PdfDocument pdfDocument)
at iText.Html2pdf.HtmlConverter.ConvertToPdf(String html, PdfDocument pdfDocument, ConverterProperties converterProperties)
at iTextSample.ConsoleApp.HtmlToPdfBuilder.RenderPdf() in C:\code\iTextSample.ConsoleApp\HtmlToPdfBuilder.cs:line 227
After some investigation found that <br /> tag was a problem. I removed all <br /> tags and it is working fine.
i'm trying to get a PDF report using Jasper in my Java web application but i'm facing to an null pointer exception and i'm not able to find which is the error.
here below my code :
private void caricaReport() {
try{
InputStream is = getClass().getResourceAsStream("reports/miooperearte.jasper");
File OutDir = new File(outputDir);
File outDir = new File(outputDir);
outDir.mkdirs();
OutputStream os = new FileOutputStream(new File(outDir, "testReportNadia.pdf"));
HashMap parameterMap = new HashMap();
parameterMap.put("immagini_base_dir", "/Applications/MAMP/htdocs/Dboperearte/app/webroot/images/");
Collection data = leggiOpere();
JRBeanCollectionDataSource dataSource = new JRBeanCollectionDataSource(data,false);
JasperRunManager.runReportToPdfStream(is, os, parameterMap, dataSource);
}
catch (Exception e) {
e.printStackTrace();
}
}
variables "is", "os", "parameterMap" and "dataSource" are all filled, exception doesn't show which is the null problem only say null pointer exception...
any idea which can help me to solve or find the problem ?
Thanks
I would guess that the parameterMap doesn't contain an entry for something that the JasperRunManager is expecting - make sure you aren't missing any values from there.
I'm using lucene to query from wiki dump and get the categories out. So, I get the relevant documents and for every document, I call the below function.
static List<String> getCategories(Document document) throws IOException
{
List<String> categories = new ArrayList<String>();
String text = document.get("text");
WikipediaTokenizer tf = new WikipediaTokenizer(new StringReader(text));
CharTermAttribute termAtt = tf.addAttribute(CharTermAttribute.class);
TypeAttribute typeAtt = tf.addAttribute(TypeAttribute.class);
while (tf.incrementToken())
{
String tokText = termAtt.toString();
if (typeAtt.type().equals(WikipediaTokenizer.CATEGORY) == true)
{
categories.add(tokText);
}
}
return categories;
}
but it throws the following error at the while statement.
Exception in thread "main" java.lang.NullPointerException
at org.apache.lucene.analysis.wikipedia.WikipediaTokenizerImpl.zzRefill(WikipediaTokenizerImpl.java:574)
at org.apache.lucene.analysis.wikipedia.WikipediaTokenizerImpl.getNextToken(WikipediaTokenizerImpl.java:781)
at org.apache.lucene.analysis.wikipedia.WikipediaTokenizer.incrementToken(WikipediaTokenizer.java:200)
at SearchIndex.getCategories(SearchIndex.java:82)
at SearchIndex.main(SearchIndex.java:54)
I looked at zzRefill() function but it I'm not able to understand it. Is this a known bug or something? I don't know what am I doing wrong. The lucene guys says that the whole wikipediaTokenizer section is in beta and maybe be subject to changes. I was hoping someone could help me.
I solved the problem by adding tf.reset() before calling the while loop
i'm working at a little drools project and i have following problem:
- when i read the knowledgepackages from drools via the knowledgeAgent it takes a long time to load((now i know that building the knowledgeBase in general and especially when loading packages from guvnor is very intense ))
so I'm trying to serialize the KnowledgeBase to a file which is located locally on the system - on the one hand because loading the kBase from a local file is much much faster - and for the other so that i can use the KnowledgeBase for other applications The Problem with this is, that while using the KnowledgeAgent to load the KnowledgeBase the first time, the base will be updated by the Agent automatically
BUT: whilst the Base is updated, my local file will not be updated too
So I'm wondering how to handle/get the changeNotification from my KnowledgeAgent so i can call a method to serialize my KnowledgeBase ?
Is this somehow possible? basically i just want to update my local knowledgeBase file, everytime someone edits a rule in governor, so that my local file is always up to date.
If it isn't possible, or a really bad solution to begin with, what is the recommended / best way to go about it?
Please endure my english and the question itself, if you cant really make out what i want to accomplish or if my request is actually not a good solution or the question itself is redundant, im rather new to java and a total noob when it comes to drools.
Down below is the code:
public class DroolsConnection {
private static KnowledgeAgent kAgent;
private static KnowledgeBase kAgentBase;
public DroolsConnection(){
ResourceFactory.getResourceChangeNotifierService().start();
ResourceFactory.getResourceChangeScannerService() .start();
}
public KnowledgeBase readKnowledgeBase( ) throws Exception {
kAgent = KnowledgeAgentFactory.newKnowledgeAgent("guvnorAgent");
kAgent .applyChangeSet( ResourceFactory.newFileResource(CHANGESET_PATH));
kAgent.monitorResourceChangeEvents(true);
kAgentBase = kAgent.getKnowledgeBase();
serializeKnowledgeBase(kAgentBase);
return kAgentBase;
}
public List<EvaluationObject> runAgainstRules( List<EvaluationObject> objectsToEvaluate,
KnowledgeBase kBase ) throws Exception{
StatefulKnowledgeSession knowSession = kBase.newStatefulKnowledgeSession();
KnowledgeRuntimeLogger knowLogger = KnowledgeRuntimeLoggerFactory.newFileLogger(knowSession, "logger");
for ( EvaluationObject o : objectsToEvaluate ){
knowSession.insert( o );
}
knowSession.fireAllRules();
knowLogger .close();
knowSession.dispose();
return objectsToEvaluate;
}
public KnowledgeBase serializeKnowledgeBase(KnowledgeBase kBase) throws IOException{
OutputStream outStream = new FileOutputStream( SERIALIZE_BASE_PATH );
ObjectOutputStream oos = new ObjectOutputStream( outStream );
oos.writeObject ( kBase );
oos.close();
return kBase;
}
public KnowledgeBase loadFromSerializedKnowledgeBase() throws Exception {
KnowledgeBase kBase = KnowledgeBaseFactory.newKnowledgeBase();
InputStream is = new FileInputStream( SERIALIZE_BASE_PATH );
ObjectInputStream ois = new ObjectInputStream( is );
kBase = (KnowledgeBase) ois.readObject();
ois.close();
return kBase;
}
}
thanks for your help in advance!
best regards,
Marenko
In order to keep your local kbase updated you could use a KnowledgeAgentEventListener to know when its internal kbase gets updated:
kagent.addEventListener( new KnowledgeAgentEventListener() {
public void beforeChangeSetApplied(BeforeChangeSetAppliedEvent event) {
}
public synchronized void afterChangeSetApplied(AfterChangeSetAppliedEvent event) {
}
public void beforeChangeSetProcessed(BeforeChangeSetProcessedEvent event) {
}
public void afterChangeSetProcessed(AfterChangeSetProcessedEvent event) {
}
public void beforeResourceProcessed(BeforeResourceProcessedEvent event) {
}
public void afterResourceProcessed(AfterResourceProcessedEvent event) {
}
public void knowledgeBaseUpdated(KnowledgeBaseUpdatedEvent event) {
//THIS IS THE EVENT YOU ARE INTERESTED IN
}
public void resourceCompilationFailed(ResourceCompilationFailedEvent event) {
}
} );
You still need to handle concurrently accesses on your local kbase though.
By the way, since you are not using 'newInstance' configuration option, the agent will create a new instance of a kbase each time a change-set is applied. So, make sure you serialize the kagent's internal kbase (kagent.getKnowledgeBase()) instead of the reference you have in your app.
Hope it helps,