In my current application i have a service which uses a saxparser to read some xml. In saxparser i try to store a new objectto the database but i get the following error:
ERROR util.JDBCExceptionReporter - Connection is read-only. Queries leading to data modification are not allowed
My Service looks like so:
#Transactional
class SchedulingService {
def printIets() {
LessonParser par = new LessonParser()
print "de service macheert ier e trut"
par.parse(["src/data/tweede/"])
}
}
The parser:
class LessonParser {
public void parse(baseFileLocations){
....
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
LessonHandler handler = new LessonHandler()
saxParser.parse(is, handler);
...
}
}
And finally the handler where the attempt to save something to the database is made
class LessonHandler extends DefaultHandler{
#Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (qName.equalsIgnoreCase("TTSession")) {
//voorlopig enkel hoorcolleges
if (parse && this.courseType == CourseType.HC) {
Course course = new Course (name:this.name , info:this.info,courseType:this.courseType,creator:this.creator)
course.save()
}
}
}
}
The error occurs when i try to save a course in the above handler.
Also i'm using a mysql database
I had connected the service to a restful api, i forgot an #transactional definition there. Adding it did the trick
Thanks for sharing.
the service got a "#Transactional(readOnly = true)" definition. So all the methods will be read only.
If you want to do some modification, you need to add "#Transactional" before the method.
Related
I am trying to write integration test case for one of my rest application which uses mongodb internally to persist the data
#DataMongoTest
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class MainControllerTest {
#LocalServerPort
private int port = 8080;
/* some test cases*/
}
but I am getting below error
java.lang.IllegalStateException: Configuration error: found multiple declarations of #BootstrapWith for test class [com.sample.core.controller.MainControllerTest]: [#org.springframework.test.context.BootstrapWith(value=class org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTestContextBootstrapper), #org.springframework.test.context.BootstrapWith(value=class org.springframework.boot.test.context.SpringBootTestContextBootstrapper)]
looks like these two are mutually exclusive, so how to do the integration testing .
Use #AutoConfigureDataMongo with #SpringBootTest and this will resolve this ambiguity issue. #SpringBootTest and #DataMongoTest cannot be used together.
Answering to a very old post hoping it may help others.
#AutoConfigureDataMongo will connect to real database. In order to still use the embedded mongo, one can initiate the embedded mongoDb manually.
#SpringBootTest(classes = SubscriptionEventApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class SubscriptionEventApiIntegrationTest {
#BeforeAll
static void setup() throws Exception {
startEmbeddedMongoDbManually();
}
private static void startEmbeddedMongoDbManually() throws IOException {
final String connectionString = "mongodb://%s:%d";
final String ip = "localhost";
final int port = 27017;
ImmutableMongodConfig mongodConfig = MongodConfig
.builder()
.version(Version.V3_5_5)
.net(new Net(ip, port, Network.localhostIsIPv6()))
.build();
MongodStarter starter = MongodStarter.getDefaultInstance();
mongodExecutable = starter.prepare(mongodConfig);
mongodExecutable.start();
mongoTemplate = new MongoTemplate(MongoClients.create(String.format(connectionString, ip, port)), "test");
}
#AfterAll
static void clean() {
mongodExecutable.stop();
}
#Test
public void test() {
.....
}
}
Purushothaman suggested starting embedded MongoDB server manually. I am suggesting to start it automatically using #DataMongoTest, but creating WebTestClient manually instead.
Kotlin code below, translates to Java trivially:
#DataMongoTest
// #ContextConfiguration may not be needed for your case.
#ContextConfiguration(
classes = [
Application::class,
MainController::class,
// Add more needed classes for your tests here.
// ...
]
)
#TestPropertySource(properties = ["spring.mongodb.embedded.version=4.0.12"])
class MainControllerTest(
#Autowired
private val mainController: MainController,
// Add more beans needed for your tests here.
// ...
) {
// Creating a WebTestClient is easy and
// can be done in different ways.
// Here is one of the possible ways.
private val webTestClient: WebTestClient =
WebTestClient.bindToController(mainController).build()
#Test
fun someTest() {
// ...
}
}
I'm a little bit new to all of these technologies so I'll try to be as clear as I can.
I'm writing a windows phone app that sends data in string format to a server:
public class sendDataControl
{
private string response = "";
public void sendToServer(string FullSTR)
{
try
{
WebClient webClient = new WebClient();
Uri uri = new Uri("http://pricequeryserver.azurewebsites.net/api/ReceiptDataService/?incomingdata=");
webClient.UploadStringAsync(uri,FullSTR);
webClient.UploadStringCompleted += new UploadStringCompletedEventHandler(webClient_UploadStringCompleted);
}
catch (Exception ex)
...
...
}
}
void webClient_UploadStringCompleted(object sender, UploadStringCompletedEventArgs e)
{
if (e.Error != null)
{
responseXml=e.Error.Message;
MessageBox.Show(responseXml);
return;
}
else
{
responseXml = e.Result;
}
}
}
The server is an MVC4, basic, with api controller I added, that needs to get the data sent from the mobile.
As a test I'm just getting back a string that I send:
public class ReceiptDataServiceController : ApiController
{
private ReceiptContext db = new ReceiptContext();
...
...
public string GetDataFromMobile(string IncomingData)
{
return IncomingData;
}
}
While running the application I get an error via responseXml:
"The remote server returned an error: NotFound".
The server returns the right answer from all kinds of browsers, while on IIS and on the azure but not from the mobile emulator.
Any suggestions?
If you take a look at the documentation for UploadStringAsync overload you are using, you will notice that it sends data using POST method. While in your controller you have only implemented GET. And for your
You have to use other overload of UploadStringAsync, which lets you specify the HTTP VERB to use. And you must specify GET. Your client code should be converted to:
webClient.UploadStringAsync(uri,"GET", FullSTR);
And the best solution for simple GET operations like your is to actually use DownloadStringAsync:
var fullUri = new Uri("http://pricequeryserver.azurewebsites.net/api/ReceiptDataService/?incomingdata=" + FullStr);
webClient.DownloadStringAsync(fullUri);
Anyway, your question has nothing to do with Windows Azure, thus the removed tag.
I've run into a weird problem.
I use Jersey 2.2 to do my restful web services (with jersey-media-moxy).
If I produce my output as application/xml, it runs fine.
But if produce my output as application/json, I get "Internal Server Error 500".
My dependency settings in ivy.xml are:
<dependency org="org.glassfish.jersey.core" name="jersey-server" rev="2.2"/>
<dependency org="org.glassfish.jersey.containers" name="jersey-container-servlet-core" rev="2.2"/>
<dependency org="org.glassfish.jersey.media" name="jersey-media-moxy" rev="2.2"/>
My service class is:
#Path("/projects/{companykey: [0-9]*}")
#Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public class ProjectResource {
private static Logger logger = Logger.getLogger(ProjectResource.class);
private final Application app = Application.getInstance();
#GET
public List<ProjectBase> getProjectBases(
#PathParam("companykey") String companyKeyStr) {
...
}
#GET
#Path("/{projectkey: [0-9]*}")
public ProjectBase getProjectBase(
#PathParam("companykey") String companyKeyStr,
#PathParam("projectkey") String projectKeyStr) {
int companyKey = Integer.valueOf(companyKeyStr);
int projObjKey = Integer.valueOf(projectKeyStr);
logger.debug(MessageFormat.format("get project {1} of company {0}",
companyKey, projObjKey));
ProjectBase project = null;
try {
project = app.getProjectIF().getProjectBase(companyKey, projObjKey);
if (project == null) throw new WebApplicationException(404);
return project;
} catch (ServerException se) {
logger.warn("get project fails ! " + se);
throw new WebApplicationException(500);
}
}
...
}
//class end
If I ask for the xml output (visit http://biz.loc.net:8080/tm/rest/projects/100/104), I get:
<projectBase>
<_checkTopicAccess>false</_checkTopicAccess>
<_checkTaskAccess>false</_checkTaskAccess>
....
If I ask for the json output, I get:
HTTP Status 500 - Internal Server Error
type Status report
message Internal Server Error
description The server encountered an internal error (Internal Server Error) that prevented it from fulfilling this request.
I do not find any error messages in my app's log file or Tomcat's log file, so I have no
idea what is going on.
Does anyone know any possible reason for this problem? Really appreciate ...
Can you show the entity code? Are you missing an empty constructor?
Thanks for your help, the following code snippet is my entity clas:
#XmlRootElement
public class ProjectBase implements UdaEnabled, SdaEnabled, FormBean {
private int projObjKey;
private String projName;
//...
private Timestamp createdAt;
//...
//...
#XmlElement(name = "createdAt")
#XmlJavaTypeAdapter(TimestampAdapter.class)
public Timestamp getCreatedAt() {
return createdAt;
}
// non-args Constructor
public ProjectBase() {
init();
}
}
It does has an empty constructor, although these's a init() inside.
As I said, I think it is weird because producing xml is OK.
I am writing integration tests to test existing Routes. The recommended way of getting the response looks something like this (via Camel In Action section 6.4.1):
public class TestGetClaim extends CamelTestSupport {
#Produce(uri = "seda:getClaimListStart")
protected ProducerTemplate producer;
#Test
public void testNormalClient() {
NotifyBuilder notify = new NotifyBuilder(context).whenDone(1).create();
producer.sendBody(new ClientRequestBean("TESTCLIENT", "Y", "A"));
boolean matches = notify.matches(5, TimeUnit.SECONDS);
assertTrue(matches);
BrowsableEndpoint be = context.getEndpoint("seda:getClaimListResponse", BrowsableEndpoint.class);
List<Exchange> list = be.getExchanges();
assertEquals(1, list.size());
System.out.println("***RESPONSE is type "+list.get(0).getIn().getBody().getClass().getName());
}
}
The test runs but I get nothing back. The assertTrue(matches) fails after the 5 second timeout.
If I rewrite the test to look like this I get a response:
#Test
public void testNormalClient() {
producer.sendBody(new ClientRequestBean("TESTCLIENT", "Y", "A"));
Object resp = context.createConsumerTemplate().receiveBody("seda:getClaimListResponse");
System.out.println("***RESPONSE is type "+resp.getClass().getName());
}
The documentation is a little light around this so can anyone tell me what I am doing wrong with the first approach? Is there anything wrong with following the second approach instead?
Thanks.
UPDATE
I have broken this down and it looks like the problem is with the mix of seda as the start endpoint in combination with the use of a recipientList in the Route. I've also changed the construction of the NotifyBuilder (I had the wrong endpoint specified).
If I change the start endpoint to
direct instead of seda then the test will work; or
If I comment out the recipientList
then the test will work.
Here's a stripped down version of my Route that reproduces this issue:
public class TestRouteBuilder extends RouteBuilder {
#Override
public void configure() throws Exception {
// from("direct:start") //works
from("seda:start") //doesn't work
.recipientList(simple("exec:GetClaimList.bat?useStderrOnEmptyStdout=true&args=${body.client}"))
.to("seda:finish");
}
}
Note that if I change the source code of the NotifyTest from the "Camel In Action" source to have a route builder like this then it also fails.
Try to use "seda:getClaimListResponse" in the getEndpoint to be sure the endpoint uri is 100% correct
FWIW: It appears that notifyBuilder in conjunction with seda queues are not quite working: a test class to illustrate:
public class NotifyBuilderTest extends CamelTestSupport {
// Try these out!
// String inputURI = "seda:foo"; // Fails
// String inputURI = "direct:foo"; // Passes
#Test
public void testNotifyBuilder() {
NotifyBuilder b = new NotifyBuilder(context).from(inputURI)
.whenExactlyCompleted(1).create();
assertFalse( b.matches() );
template.sendBody(inputURI, "Test");
assertTrue( b.matches() );
b.reset();
assertFalse( b.matches() );
template.sendBody(inputURI, "Test2");
assertTrue( b.matches() );
}
#Override
protected RouteBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
#Override
public void configure() throws Exception {
from(inputURI).to("mock:foo");
}
};
}
}
I just started using LINQ to SQL classes, and really like how this helps me write readable code.
In the documentation, typical examples state that to do custom validation, you create a partial class as so::
partial class Customer
{
partial void OnCustomerIDChanging(string value)
{
if (value=="BADVALUE") throw new NotImplementedException("CustomerID Invalid");
}
}
And similarly for other fields...
And then in the codebehind, i put something like this to display the error message and keep the user on same page so to correct the mistake.
public void CustomerListView_OnItemInserted(object sender, ListViewInsertedEventArgs e)
{
string errorString = "";
if (e.Exception != null)
{
e.KeepInInsertMode = true;
errorString += e.Exception.Message;
e.ExceptionHandled = true;
}
else errorString += "Successfully inserted Customer Data" + "\n";
errorMessage.Text = errorString;
}
Okay, that's easy, but then it stops validating the rest of the fields as soon as the first Exception is thrown!! Mean if the user made mode than one mistake, she/he/it will only be notified of the first error.
Is there another way to check all the input and show the errors in each ?
Any suggestions appreciated, thanks.
This looks like a job for the Enterprise Library Validation Application Block (VAB). VAB has been designed to return all errors. Besides this, it doesn't thrown an exception, so you can simply ask it to validate the type for you.
When you decide to use the VAB, I advise you to -not- use the OnXXXChanging and OnValidate methods of LINQ to SQL. It's best to override the SubmitChange(ConflictMode) method on the DataContext class to call into VAB's validation API. This keeps your validation logic out of your business entities, which keeps your entities clean.
Look at the following example:
public partial class NorthwindDataContext
{
public ValidationResult[] Validate()
{
return invalidResults = (
from entity in this.GetChangedEntities()
let type = entity.GetType()
let validator = ValidationFactory.CreateValidator(type)
let results = validator.Validate(entity)
where !results.IsValid
from result in results
select result).ToArray();
}
public override void SubmitChanges(ConflictMode failureMode)
{
ValidationResult[] this.Validate();
if (invalidResults.Length > 0)
{
// You should define this exception type
throw new ValidationException(invalidResults);
}
base.SubmitChanges(failureMode);
}
private IEnumerable<object> GetChangedEntities()
{
ChangeSet changes = this.GetChangeSet();
return changes.Inserts.Concat(changes.Updates);
}
}
[Serializable]
public class ValidationException : Exception
{
public ValidationException(IEnumerable<ValidationResult> results)
: base("There are validation errors.")
{
this.Results = new ReadOnlyCollection<ValidationResult>(
results.ToArray());
}
public ReadOnlyCollection<ValidationResult> Results
{
get; private set;
}
}
Calling the Validate() method will return a collection of all errors, but rather than calling Validate(), I'd simply call SubmitChanges() when you're ready to persist. SubmitChanges() will now check for errors and throw an exception when one of the entities is invalid. Because the list of errors is sent to the ValidationException, you can iterate over the errors higher up the call stack, and present them to the user, as follows:
try
{
db.SubmitChanges();
}
catch (ValidationException vex)
{
ShowErrors(vex.ValidationErrors);
}
private static void ShowErrors(IEnumerable<ValidationResult> errors)
{
foreach(var error in errors)
{
Console.WriteLine("{0}: {1}", error.Key, error.message);
}
}
When you use this approach you make sure that your entities are always validated before saving them to the database
Here is a good article that explains how to integrate VAB with LINQ to SQL. You should definitely read it if you want to use VAB with LINQ to SQL.
Not with LINQ. Presumably you would validate the input before giving it to LINQ.
What you're seeing is natural behaviour with exceptions.
I figured it out. Instead of throwing an exception at first failed validation, i store an error message in a class with static variable. to do this, i extend the DataContext class like this::
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
/// <summary>
/// Summary description for SalesClassesDataContext
/// </summary>
public partial class SalesClassesDataContext
{
public class ErrorBox
{
private static List<string> Messages = new List<string>();
public void addMessage(string message)
{
Messages.Add(message);
}
public List<string> getMessages()
{
return Messages;
}
}
}
in the classes corresponding to each table, i would inherit the newly defined class like this::
public partial class Customer : SalesClassesDataContext.ErrorBox
only in the function OnValidate i would throw an exception in case the number of errors is not 0. Hence not attempting to insert, and keeping the user on same input page, without loosing the data they entered.