Using db4o client/server, updates are not working for collection properties of an object. I'm using transparent persistence, but that's not helping. Then, I changed my Collection property to ActivatableCollection, but no luck.
This is the server setup:
private void StartDatabase()
{
IServerConfiguration serverConfiguration = Db4oClientServer.NewServerConfiguration();
serverConfiguration.Networking.MessageRecipient = this;
serverConfiguration.Common.Add(new TransparentActivationSupport());
serverConfiguration.Common.Add(new TransparentPersistenceSupport());
string db4oDatabasePath = AppDomain.CurrentDomain.BaseDirectory;
string db4oDatabaseFileName = ConfigurationManager.AppSettings["db4oDatabaseFileName"];
int databaseServerPort = Convert.ToInt32(ConfigurationManager.AppSettings["databaseServerPort"], CultureInfo.InvariantCulture);
_db4oServer = Db4oClientServer.OpenServer(serverConfiguration, db4oDatabasePath + db4oDatabaseFileName, databaseServerPort);
string databaseUser = ConfigurationManager.AppSettings["databaseUser"];
string databasePassword = ConfigurationManager.AppSettings["databasePassword"];
_db4oServer.GrantAccess(databaseUser, databasePassword);
}
This is the entity that I want to save:
public class Application : ActivatableEntity
And this is the property within the Application entity:
public ActivatableCollection<TaskBase> Tasks { get; private set; }
This is the client code to update each object within the collection:
Application application = (from Application app in db
where app.Name == "Foo"
select app).FirstOrDefault();
foreach (TaskBase task in application.Tasks)
{
task.Description += ".";
}
db.Store(application);
Curiously, db.Commit() didn't work either.
There are two work-arounds, but I'd rather do this the "right" way.
Work-around 1: Call db.Store(task) on each task as the change is made.
Work-around 2: Before calling db.Store(), do this:
db.Ext().Configure().UpdateDepth(5);
Can anyone tell me why the list isn't updating?
If it helps, here is the ActivatableCollection class:
public class ActivatableCollection<T> : Collection<T>, IActivatable
{
[Transient]
private IActivator _activator;
/// <summary>
/// Activates the specified purpose.
/// </summary>
/// <param name="purpose">The purpose.</param>
public void Activate(ActivationPurpose purpose)
{
if (this._activator != null)
{
this._activator.Activate(purpose);
}
}
/// <summary>
/// Binds the specified activator.
/// </summary>
/// <param name="activator">The activator.</param>
public void Bind(IActivator activator)
{
if (_activator == activator) { return; }
if (activator != null && null != _activator) { throw new System.InvalidOperationException(); }
_activator = activator;
}
}
Indeed, transparent persistence needs a call to it's activator before every field access. However the intentions is that you do this with the enhancer-tool instead of implementing manually.
Another note: When you're using CascadeOnUpdate(true) everywhere db4o will end up storing every reachable activated object. If the object-graph is huge, this can be a major performance bottle-neck.
I was able to get transparent activation and persistence to work. I decided not to go with the approach for the reasons mentioned in my comment above. I think the easiest way to handle cascading updates is to simply use a client config like this:
IClientConfiguration clientConfig = Db4oClientServer.NewClientConfiguration();
And then either a bunch of these (this isn't so bad because we can add an attribute to every domain entity, then reflectively do this on each one):
clientConfig.Common.ObjectClass(typeof(Application)).CascadeOnUpdate(true);
Or this:
clientConfig.Common.UpdateDepth = 10;
return Db4oClientServer.OpenClient(clientConfig, databaseServerName, databaseServerPort, databaseUser, databasePassword);
Now, here is the server config that allowed me to get transparent persistence working.
private void StartDatabase()
{
IServerConfiguration serverConfiguration = Db4oClientServer.NewServerConfiguration();
serverConfiguration.Networking.MessageRecipient = this;
serverConfiguration.Common.Add(new TransparentActivationSupport());
serverConfiguration.Common.Add(new TransparentPersistenceSupport());
string db4oDatabasePath = AppDomain.CurrentDomain.BaseDirectory;
string db4oDatabaseFileName = ConfigurationManager.AppSettings["db4oDatabaseFileName"];
int databaseServerPort = Convert.ToInt32(ConfigurationManager.AppSettings["databaseServerPort"], CultureInfo.InvariantCulture);
_db4oServer = Db4oClientServer.OpenServer(serverConfiguration, db4oDatabasePath + db4oDatabaseFileName, databaseServerPort);
string databaseUser = ConfigurationManager.AppSettings["databaseUser"];
string databasePassword = ConfigurationManager.AppSettings["databasePassword"];
_db4oServer.GrantAccess(databaseUser, databasePassword);
}
Hope this helps someone.
I had the same problem with Transparent Activation and Persistence in java. I managed to get it to work cleaning the database and starting from scratch. However, no works by calling commit() after changing the object graph. You must call store() on the root object.
This is a simple example:
/*************** Item.java ******************************************/
import com.db4o.activation.ActivationPurpose;
import com.db4o.activation.Activator;
import com.db4o.collections.ActivatableSupport;
import com.db4o.ta.Activatable;
public class Item implements Activatable {
private String name;
private transient Activator activator;
public Item(String name) {
this.name = name;
}
public String getName() {
activate(ActivationPurpose.READ);
return name;
}
public void setName(String name) {
activate(ActivationPurpose.WRITE);
this.name = name;
}
#Override
public String toString() {
activate(ActivationPurpose.READ);
return "Item [name=" + name + "]";
}
public void activate(ActivationPurpose purpose) {
ActivatableSupport.activate(this.activator, purpose);
}
public void bind(Activator activator) {
this.activator = ActivatableSupport.validateForBind(this.activator, activator);
}
}
/******************* Container.java *********************************/
import java.util.Set;
import com.db4o.activation.ActivationPurpose;
import com.db4o.activation.Activator;
import com.db4o.collections.ActivatableHashSet;
import com.db4o.collections.ActivatableSupport;
import com.db4o.ta.Activatable;
public class Container implements Activatable {
private String name;
private Set<Item> items;
private transient Activator activator;
public Container() {
items = new ActivatableHashSet<Item>();
}
public String getName() {
activate(ActivationPurpose.READ);
return name;
}
public void setName(String name) {
activate(ActivationPurpose.WRITE);
this.name = name;
}
public void addItem(Item item) {
activate(ActivationPurpose.WRITE);
items.add(item);
}
public Set<Item> getItems() {
activate(ActivationPurpose.READ);
return items;
}
#Override
public String toString() {
activate(ActivationPurpose.READ);
return "Container [items=" + items + "]";
}
public void activate(ActivationPurpose purpose) {
ActivatableSupport.activate(this.activator, purpose);
}
public void bind(Activator activator) {
this.activator = ctivatableSupport.validateForBind(this.activator, activator);
}
}
/************* Main.java ********************************************/
import com.db4o.Db4oEmbedded;
import com.db4o.ObjectContainer;
import com.db4o.ObjectSet;
import com.db4o.config.EmbeddedConfiguration;
import com.db4o.ta.TransparentActivationSupport;
import com.db4o.ta.TransparentPersistenceSupport;
public class Main {
public static void main() {
EmbeddedConfiguration config = Db4oEmbedded.newConfiguration();
config.common().add(new TransparentActivationSupport());
config.common().add(new TransparentPersistenceSupport());
ObjectContainer db = Db4oEmbedded.openFile(config, System.getProperty("user.home") + "/testTP.db4o");
Container c = new Container();
c.setName("Container0");
ObjectSet<Container> result = db.queryByExample(c);
if(result.hasNext()) {
c = result.next();
System.out.println(c);
}
c.addItem(new Item("Item" + c.getItems().size()));
db.store(c);
System.out.println(c);
db.close();
}
}
Related
I'm working on making a custom properties provider to load the contents of a Spring cloud config server at startup. I need to make a single call at the initialization of the provider to fetch these properties, and would like to use the Mule HttpService in order to make the http client for this call, instead of creating my own. Unfortunately, whenever I try this, it seems the HttpService hasn't been created yet and so throws an NPE once it's referenced.
CustomConfigurationPropertiesProviderFactory.java
public class CustomConfigurationPropertiesProviderFactory implements ConfigurationPropertiesProviderFactory {
public static final String EXTENSION_NAMESPACE = "custom-properties";
public static final String CONFIGURATION_PROPERTIES_ELEMENT = "config";
public static final ComponentIdentifier CUSTOM_CONFIGURATION_PROPERTIES =
builder().namespace(EXTENSION_NAMESPACE).name(CONFIGURATION_PROPERTIES_ELEMENT).build();
#Inject
HttpService httpService;
#Override
public ComponentIdentifier getSupportedComponentIdentifier() {
return CUSTOM_CONFIGURATION_PROPERTIES;
}
#Override
public ConfigurationPropertiesProvider createProvider(ConfigurationParameters parameters,
ResourceProvider externalResourceProvider) {
String url = parameters.getStringParameter("url");
return new CustomConfigurationPropertiesProvider(url, httpService);
}
}
CustomConfigurationPropertiesProvider.java
public class CustomConfigurationPropertiesProvider implements ConfigurationPropertiesProvider {
private final static String PREFIX = "custom::";
private Properties properties = null;
public CustomConfigurationPropertiesProvider(String url, HttpService httpService) {
HttpClientConfiguration.Builder builder = new HttpClientConfiguration.Builder();
builder.setName("customProperties");
HttpClient client = httpService.getClientFactory().create(builder.build()); //NPE here
client.start();
// proceed to create and execute request, then load into properties
}
#Override
public Optional<ConfigurationProperty> getConfigurationProperty(String configurationAttributeKey) {
if (configurationAttributeKey.startsWith(PREFIX)) {
String effectiveKey = configurationAttributeKey.substring(PREFIX.length());
if (properties != null && !properties.isEmpty()) {
return Optional.of(new ConfigurationProperty() {
#Override
public Object getSource() {...}
#Override
public Object getRawValue() { return properties.getProperty(effectiveKey); }
#Override
public String getKey() { return effectiveKey; }
});
}
}
return Optional.empty();
}
}
What do I need to change to properly inject this service?
I've been following the advice from these two bits of documentation, for reference:
https://docs.mulesoft.com/mule-runtime/4.2/custom-configuration-properties-provider
https://docs.mulesoft.com/mule-sdk/1.1/mule-service-injection
I am using springfox version 2.9.2 and swagger annotations 1.5.x. The ApiModel annotations support the discriminator, subTypes and parent attribute which are required to make polymorphism work but I am not seeing the correct apidocs generated to enable polymorphism.
Here is my annotated code.
#RestController
#RequestMapping("/api/vehicles")
public class VehicleController {
private static final Logger LOGGER = LoggerFactory.getLogger(VehicleController.class);
#PostMapping(consumes = {MediaType.APPLICATION_JSON_UTF8_VALUE})
void post(#RequestBody Vehicle anyVehicle) {
LOGGER.info("Vehicle : {}", anyVehicle);
}
}
#ApiModel(discriminator = "type", subTypes = {Car.class, Bike.class})
public class Vehicle {
String brand;
String type;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
#ApiModel(parent = Vehicle.class)
public class Car extends Vehicle {
int noOfDoors;
boolean powerWindows;
public int getNoOfDoors() {
return noOfDoors;
}
public void setNoOfDoors(int noOfDoors) {
this.noOfDoors = noOfDoors;
}
public boolean isPowerWindows() {
return powerWindows;
}
public void setPowerWindows(boolean powerWindows) {
this.powerWindows = powerWindows;
}
}
#ApiModel(parent = Vehicle.class)
public class Bike extends Vehicle {
boolean pillion;
public boolean isPillion() {
return pillion;
}
public void setPillion(boolean pillion) {
this.pillion = pillion;
}
}
When the docs get generated is basically shows one endpoint which handles a POST request and takes in a Vehicle as the model.
Is what I am doing here supposed to work? Can someone point me to a working example of this with SpringFox that I can look at?
Support for discriminator is not available in Swagger UI yet. You can follow these issues for status updates:
Discriminator does not switch schema
subTypes not displayed in model
I was trying to map ResultSet data to an object and returning it. Here is how i'm mapping data to an object. Now i'm having only 7 columns in resultset so this is working fine but what if i'm having 20 or 30 columns. How can i map dynamically those columns.
public class ProductsWrapperMapper implements ResultSetMapper<ProductsWrapper> {
public ProductsWrapper map(int i, ResultSet resultSet,
StatementContext statementContext) throws SQLException {
ProductsWrapper product = new ProductsWrapper();
if ((isColumnPresent(resultSet,"a_productid"))) {
product.setId(resultSet.getInt("a_productid"));
}
if ((isColumnPresent(resultSet,"a_productname"))) {
product.setProductName(resultSet.getString("a_productname"));
}
if ((isColumnPresent(resultSet,"a_productlink"))) {
product.setLink(resultSet.getString("a_productlink"));
}
if ((isColumnPresent(resultSet,"a_productimagelink"))) {
product.setImageLink(resultSet.getString("a_productimagelink"));
}
if ((isColumnPresent(resultSet,"a_websiteid"))) {
product.setWebsiteId(resultSet.getInt("a_websiteid"));
}
if ((isColumnPresent(resultSet,"a_productidentification"))) {
product.setProductIdentification(resultSet
.getString("a_productidentification"));
}
if ((isColumnPresent(resultSet,"a_adddate"))) {
product.setAddDate(resultSet.getString("a_adddate"));
}
return product;
}
public boolean isColumnPresent(ResultSet resultSet,String column) {
try {
#SuppressWarnings("unused")
int index = resultSet.findColumn(column);
return true;
} catch (SQLException e) {
// TODO Auto-generated catch block
return false;
}
}
}
Below one is my class which i was returning the object from mapper class above.
#JsonInclude(Include.NON_NULL)
public class ProductsWrapper {
private int id;
private String productName;
private String link;
private String imageLink;
private int websiteId;
private String productIdentification;
private String addDate;
int getWebsiteId() {
return websiteId;
}
public void setWebsiteId(int websiteId) {
this.websiteId = websiteId;
}
public String getProductIdentification() {
return productIdentification;
}
public void setProductIdentification(String productIdentification) {
this.productIdentification = productIdentification;
}
public String getAddDate() {
return addDate;
}
public void setAddDate(String addDate) {
this.addDate = addDate;
}`enter code here`
public ProductsWrapper(int id) {
this.setId(id);
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
public String getImageLink() {
return imageLink;
}
public void setImageLink(String imageLink) {
this.imageLink = imageLink;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
You can also try Jdbi-folder. It automatically takes care of dynamic bynding and also it provides one to many mapping relationship.
You can add Rosetta as a mapper for your JDBI result sets (it also works for bindings). Have a look at the advanced features to map column names with underscores to snake snake case java names.
Beware that there is no warning message if Rosetta is unable to map a value: any missed property in the target bean will just be empty. I found that my database returned column names in capital letters, therefore the LowerCaseWithUnderscoresStrategy in the example didn't work for me. I created a UpperCaseWithUnderscoresStrategy.
To skip writing getters and setters in ProductsWrapper have a look at Lombok's #Data annotation.
I want to get the instance of the Entity from SelectOneMenu so i can assign the entity variables to some other method. But it is pointing to null.
xhtml code
<h:selectOneMenu value="#{statusReport.projectDetID}" converter="ObjectStringConv" onchange="#{statusReport.retrieveReport()}" >
<f:selectItems value="#{statusReport.listOfProjectDetail}"
var="projectDetail" itemLabel="#{projectDetail.project} #{projectDetail.startDate} - #{projectDetail.endDate}"
itemValue="#{projectDetail}" noSelectionValue="Select the Saved Project"/>
</h:selectOneMenu>
statusReport bean
public class StatusReport implements Serializable {
private ProjectDetail projectDetID;
private List<ProjectDetail> listOfProjectDetail;
public List<ProjectDetail> getListOfProjectDetail() {
listOfProjectDetail = projectDetailFacade.findAll();
return listOfProjectDetail;
}
public void setListOfProjectDetail(List<ProjectDetail> listOfProjectDetail) {
this.listOfProjectDetail = listOfProjectDetail;
}
public ProjectDetail getProjectDetID() {
return projectDetID;
}
public void setProjectDetID(ProjectDetail projectDetID) {
this.projectDetID = projectDetID;
}
public void retrieveReport(){
System.out.println(" Processing .....");
if ( projectDetID == null )
{
System.out.println("The object from Select null");
}
else
{
System.out.println("The object from Select menu" + projectDetID.toString());
}
System.out.println("Generated Data:Completed");
}}
ProjectDetail Entity Bean
package com.jira.entity;
import java.io.Serializable;
import javax.persistence.*;
import java.util.Date;
import java.util.List;
/**
* The persistent class for the PROJECT_DETAIL database table.
*
*/
#Entity
#Table(name="PROJECT_DETAIL",schema="weeklyrep")
public class ProjectDetail implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="projectdetail_seq")
#SequenceGenerator(name="projectdetail_seq",schema="weeklyrep",sequenceName="projectdetail_seq", allocationSize=1)
#Column(name="PDETAIL_ID")
private long pdetailId;
private Boolean completed;
#Temporal( TemporalType.DATE)
#Column(name="END_DATE")
private Date endDate;
private Long project;
#Temporal( TemporalType.DATE)
#Column(name="START_DATE")
private Date startDate;
//bi-directional many-to-one association to MajorEvent
#OneToMany(mappedBy="projectDetail",cascade=CascadeType.ALL)
private List<MajorEvent> majorEvents;
//bi-directional one-to-one association to ExecSummary
#OneToOne(mappedBy="projectDetailExec",cascade=CascadeType.ALL)
private ExecSummary execSummary;
public ProjectDetail() {
}
public long getPdetailId() {
return this.pdetailId;
}
public void setPdetailId(Long pdetailId) {
this.pdetailId = pdetailId;
}
public Boolean getCompleted() {
return this.completed;
}
public void setCompleted(Boolean completed) {
this.completed = completed;
}
public Date getEndDate() {
return this.endDate;
}
public void setEndDate(Date endDate) {
this.endDate = endDate;
}
public long getProject() {
return this.project;
}
public void setProject(long project) {
this.project = project;
}
public Date getStartDate() {
return this.startDate;
}
public void setStartDate(Date startDate) {
this.startDate = startDate;
}
public List<MajorEvent> getMajorEvents() {
return this.majorEvents;
}
public void setMajorEvents(List<MajorEvent> majorEvents) {
this.majorEvents = majorEvents;
}
public ExecSummary getExecSummary() {
return execSummary;
}
public void setExecSummary(ExecSummary execSummary) {
this.execSummary = execSummary;
}
}
Converter
I don't know if it needs converter, however i don't know how code it.
package com.weeklyreport.converters;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
import com.jira.entity.ProjectDetail;
#FacesConverter(value="ObjectStringConv")
public class ObjectStringConv implements Converter {
#Override
public Object getAsObject(FacesContext context, UIComponent component, String svalue) {
System.out.print("String version of object is:" + svalue);
return "test";
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object ovalue) {
return ovalue.toString();
}
}
Please help me figure this out. Is there a way we get instance of the entity object like this?
Your converter needs to be written that way so that it can convert between ProjectDetail and String based on an unique identifier of ProjectDetail. Usually entities have an id. You need to use this as String value. Here's a kickoff example without any trivial checks like null and instanceof:
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
// Convert ProjectDetail to its unique String representation.
ProjectDetail projectDetail = (ProjectDetail) value;
String idAsString = String.valueOf(projectDetail.getId())
return idAsString;
}
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
// Convert unique String representation of ProjectDetail back to ProjectDetail object.
Long id = Long.valueOf(value);
ProjectDetail projectDetail = someProjectDetailService.find(id);
return projectDetail;
}
Note that using EJBs in JSF converters (and validators) needs some hackery. See also How to inject #EJB, #PersistenceContext, #Inject, #Autowired, etc in #FacesConverter?
This Question may be asked in several threads...but could not fine the correct answer
a Java Bean
package com.example;
public class Document {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
An ArrayList creation of JavaBean as displayed below
package com.example;
import java.util.ArrayList;
public class classdocs {
public ArrayList getData() {
ArrayList docsmx = new ArrayList();
Document d1 = new Document();
d1.setName("user.doc");
Document d2 = new Document();
d2.setName("office.doc");
Document d3 = new Document();
d3.setName("transactions.doc");
docsmx.add(d1);
docsmx.add(d2);
docsmx.add(d3);
return docsmx;
}
}
an Action Class
package com.example;
import java.util.ArrayList;
import com.opensymphony.xwork2.ActionSupport;
public class FetchAction extends ActionSupport {
private String username;
private String message;
private ArrayList docsmx = new ArrayList();
public ArrayList getDocuments() {
return docsmx;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String execute() {
classdocs cx = new classdocs();
if( username != null) {
docsmx = cx.getData();
return "success";
} else {
message="Unable to fetch";
return "failure";
}
}
}
Jsp with Struts2 Iterator Tag
Documents uploaded by the user are:</br>
<s:iterator value="docsmx">
<s:property value="name" /></br>
</s:iterator>
Question Why the ArrayList of Bucket containing JavaBean not displayed when Iterated ...
Am I doing some thing wrong ???
with regards
karthik
Depending your version, you should either provide a getter for docsmx (preferred, pre-S2.1.mumble), or make docsmx public (not as preferred, S2.1+).
Or, based on your code, use the correct getter:
<s:iterator value="documents">
<s:property value="name" /></br>
</s:iterator>
A couple of notes: documents should likely be declared a List, not ArrayList, although in this case it almost certainly doesn't matter. It's a good habit to get in to, though, coding to an interface when the implementation doesn't matter.
I'd also consider tightening up the code a little bit:
public String execute() {
if (username == null) {
message = "Unable to fetch";
return "failure";
}
docsmx = cs.getData();
return "success";
}
This allows a more natural reading, makes it more clear what the two states are (success and failure), keeps them very distinct, and slightly shorter.