// If we're becoming coordinator, we need to handle TMP_VIEW as // an immediate change of view. See JGRP-1452. private void handleTmpView(View v) { List<Address> mbrs = v.getMembers(); if (mbrs.isEmpty()) return; Address new_coord = mbrs.get(0); if (!new_coord.equals(coord) && local_addr != null && local_addr.equals(new_coord)) handleViewChange(v); }
public void sendGetMembersRequest(String cluster_name, Promise promise, boolean return_views_only) throws Exception { PhysicalAddress physical_addr = (PhysicalAddress) down_prot.down(new Event(Event.GET_PHYSICAL_ADDRESS, local_addr)); PingData data = new PingData(local_addr, null, false, UUID.get(local_addr), Arrays.asList(physical_addr)); PingHeader hdr = new PingHeader(PingHeader.GET_MBRS_REQ, data, cluster_name); hdr.return_view_only = return_views_only; Set<PhysicalAddress> combined_target_members = new HashSet<PhysicalAddress>(initial_hosts); combined_target_members.addAll(dynamic_hosts); for (final Address addr : combined_target_members) { if (addr.equals(physical_addr)) continue; final Message msg = new Message(addr, null, null); msg.setFlag(Message.OOB); msg.putHeader(this.id, hdr); if (log.isTraceEnabled()) log.trace("[FIND_INITIAL_MBRS] sending PING request to " + msg.getDest()); timer.execute( new Runnable() { public void run() { try { down_prot.down(new Event(Event.MSG, msg)); } catch (Exception ex) { if (log.isErrorEnabled()) log.error("failed sending discovery request to " + addr + ": " + ex); } } }); } }
@Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; User other = (User) obj; if (Address == null) { if (other.Address != null) return false; } else if (!Address.equals(other.Address)) return false; if (CcCode == null) { if (other.CcCode != null) return false; } else if (!CcCode.equals(other.CcCode)) return false; if (Contact == null) { if (other.Contact != null) return false; } else if (!Contact.equals(other.Contact)) return false; if (CreationDate == null) { if (other.CreationDate != null) return false; } else if (!CreationDate.equals(other.CreationDate)) return false; if (ExpirationDate == null) { if (other.ExpirationDate != null) return false; } else if (!ExpirationDate.equals(other.ExpirationDate)) return false; if (FirstName == null) { if (other.FirstName != null) return false; } else if (!FirstName.equals(other.FirstName)) return false; if (LastName == null) { if (other.LastName != null) return false; } else if (!LastName.equals(other.LastName)) return false; if (SecurityCode == null) { if (other.SecurityCode != null) return false; } else if (!SecurityCode.equals(other.SecurityCode)) return false; return true; }
/** Execute when new member join or leave Group */ public void viewAccepted(View v) { memberSize = v.size(); if (mainFrame != null) setTitle(); members.clear(); members.addAll(v.getMembers()); if (v instanceof MergeView) { System.out.println("** " + v); // This is a simple merge function, which fetches the state from the coordinator // on a merge and overwrites all of its own state if (useState && !members.isEmpty()) { Address coord = members.get(0); Address local_addr = channel.getAddress(); if (local_addr != null && !local_addr.equals(coord)) { try { // make a copy of our state first Map<Point, Color> copy = null; if (send_own_state_on_merge) { synchronized (drawPanel.state) { copy = new LinkedHashMap<Point, Color>(drawPanel.state); } } System.out.println("fetching state from " + coord); channel.getState(coord, 5000); if (copy != null) sendOwnState(copy); // multicast my own state so everybody else has it too } catch (Exception e) { e.printStackTrace(); } } } } else System.out.println("** View=" + v); }
/** * An event is to be sent down the stack. The layer may want to examine its type and perform some * action on it, depending on the event's type. If the event is a message MSG, then the layer may * need to add a header to it (or do nothing at all) before sending it down the stack using <code> * PassDown</code>. In case of a GET_ADDRESS event (which tries to retrieve the stack's address * from one of the bottom layers), the layer may need to send a new response event back up the * stack using <code>up_prot.up()</code>. The PING protocol is interested in several different * down events, Event.FIND_INITIAL_MBRS - sent by the GMS layer and expecting a GET_MBRS_OK * Event.TMP_VIEW and Event.VIEW_CHANGE - a view change event Event.BECOME_SERVER - called after * client has joined and is fully working group member Event.CONNECT, Event.DISCONNECT. */ @SuppressWarnings("unchecked") public Object down(Event evt) { switch (evt.getType()) { case Event.FIND_INITIAL_MBRS: // sent by GMS layer case Event.FIND_ALL_VIEWS: // sends the GET_MBRS_REQ to all members, waits 'timeout' ms or until 'num_initial_members' // have been retrieved long start = System.currentTimeMillis(); boolean find_all_views = evt.getType() == Event.FIND_ALL_VIEWS; Promise<JoinRsp> promise = (Promise<JoinRsp>) evt.getArg(); List<PingData> rsps = find_all_views ? findAllViews(promise) : findInitialMembers(promise); long diff = System.currentTimeMillis() - start; if (log.isTraceEnabled()) log.trace("discovery took " + diff + " ms: responses: " + Util.printPingData(rsps)); return rsps; case Event.TMP_VIEW: case Event.VIEW_CHANGE: List<Address> tmp; view = (View) evt.getArg(); if ((tmp = view.getMembers()) != null) { synchronized (members) { members.clear(); members.addAll(tmp); } } current_coord = !members.isEmpty() ? members.get(0) : null; is_coord = current_coord != null && local_addr != null && current_coord.equals(local_addr); return down_prot.down(evt); case Event.BECOME_SERVER: // called after client has joined and is fully working group member down_prot.down(evt); is_server = true; return null; case Event.SET_LOCAL_ADDRESS: local_addr = (Address) evt.getArg(); return down_prot.down(evt); case Event.CONNECT: case Event.CONNECT_WITH_STATE_TRANSFER: case Event.CONNECT_USE_FLUSH: case Event.CONNECT_WITH_STATE_TRANSFER_USE_FLUSH: is_leaving = false; group_addr = (String) evt.getArg(); Object ret = down_prot.down(evt); handleConnect(); return ret; case Event.DISCONNECT: is_leaving = true; handleDisconnect(); return down_prot.down(evt); default: return down_prot.down(evt); // Pass on to the layer below us } }
protected void deliver(Message msg, Event evt, SequencerHeader hdr) { Address sender = msg.getSrc(); if (sender == null) { if (log.isErrorEnabled()) log.error(local_addr + ": sender is null, cannot deliver " + "::" + hdr.getSeqno()); return; } long msg_seqno = hdr.getSeqno(); if (sender.equals(local_addr)) { forward_table.remove(msg_seqno); if (hdr.flush_ack) { ack_promise.setResult(msg_seqno); if (ack_mode && !flushing && threshold > 0 && ++num_acks >= threshold) { ack_mode = false; num_acks = 0; } } } if (!canDeliver(sender, msg_seqno)) { if (log.isWarnEnabled()) log.warn(local_addr + ": dropped duplicate message " + sender + "::" + msg_seqno); return; } if (log.isTraceEnabled()) log.trace(local_addr + ": delivering " + sender + "::" + msg_seqno); up_prot.up(evt); delivered_bcasts++; }
/** Callback invoked by the protocol stack to deliver a message batch */ public void up(MessageBatch batch) { if (stats) { received_msgs += batch.size(); received_bytes += batch.length(); } // discard local messages (sent by myself to me) if (discard_own_messages && local_addr != null && batch.sender() != null && local_addr.equals(batch.sender())) return; for (Message msg : batch) { if (up_handler != null) { try { up_handler.up(new Event(Event.MSG, msg)); } catch (Throwable t) { log.error(Util.getMessage("UpHandlerFailure"), t); } } else if (receiver != null) { try { receiver.receive(msg); } catch (Throwable t) { log.error(Util.getMessage("ReceiverFailure"), t); } } } }
/** * Invoked upon receiving a MERGE event from the MERGE layer. Starts the merge protocol. See * description of protocol in DESIGN. * * @param views A List of <em>different</em> views detected by the merge protocol */ public void merge(Map<Address, View> views) { if (isMergeInProgress()) { if (log.isTraceEnabled()) log.trace(gms.local_addr + ": merge is already running (merge_id=" + merge_id + ")"); return; } // we need the merge *coordinators* not merge participants because not everyone can lead a merge // ! Collection<Address> coords = Util.determineMergeCoords(views); Collection<Address> merge_participants = Util.determineMergeParticipants(views); Membership tmp = new Membership(coords); // establish a deterministic order, so that coords can elect leader tmp.sort(); Address merge_leader = tmp.elementAt(0); if (log.isDebugEnabled()) log.debug("determining merge leader from " + merge_participants); if (merge_leader.equals(gms.local_addr)) { if (log.isDebugEnabled()) log.debug( "I (" + gms.local_addr + ") will be the leader. Starting the merge task for " + merge_participants); merge_task.start(views); } else { if (log.isDebugEnabled()) log.debug( "I (" + gms.local_addr + ") am not the merge leader, " + "waiting for merge leader (" + merge_leader + ") to initiate merge"); } }
@Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (!(obj instanceof Customer)) return false; Customer other = (Customer) obj; if (address == null) { if (other.address != null) return false; } else if (!address.equals(other.address)) return false; if (creditRequests == null) { if (other.creditRequests != null) return false; } else if (!creditRequests.equals(other.creditRequests)) return false; if (customerId != other.customerId) return false; if (disbursementPreference == null) { if (other.disbursementPreference != null) return false; } else if (!disbursementPreference.equals(other.disbursementPreference)) return false; if (firstName == null) { if (other.firstName != null) return false; } else if (!firstName.equals(other.firstName)) return false; if (lastName == null) { if (other.lastName != null) return false; } else if (!lastName.equals(other.lastName)) return false; if (middleName == null) { if (other.middleName != null) return false; } else if (!middleName.equals(other.middleName)) return false; if (openBalance == null) { if (other.openBalance != null) return false; } else if (!openBalance.equals(other.openBalance)) return false; if (rating == null) { if (other.rating != null) return false; } else if (!rating.equals(other.rating)) return false; return true; }
/** Checks whether the potential_new_coord would be the new coordinator (2nd in line) */ protected boolean wouldBeNewCoordinator(Address potential_new_coord) { if (potential_new_coord == null) return false; synchronized (members) { if (members.size() < 2) return false; Address new_coord = members.elementAt(1); // member at 2nd place return new_coord != null && new_coord.equals(potential_new_coord); } }
protected void handleView(View view) { view_size = view.size(); Address tmp = Util.pickNext(view.getMembers(), local_addr); if (tmp != null && !tmp.equals(local_addr)) { next = tmp; if (log.isDebugEnabled()) log.debug("next=" + next); } }
@Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; User other = (User) obj; if (address == null) { if (other.address != null) return false; } else if (!address.equals(other.address)) return false; if (companys == null) { if (other.companys != null) return false; } else if (!companys.equals(other.companys)) return false; if (competences == null) { if (other.competences != null) return false; } else if (!competences.equals(other.competences)) return false; if (country == null) { if (other.country != null) return false; } else if (!country.equals(other.country)) return false; if (description == null) { if (other.description != null) return false; } else if (!description.equals(other.description)) return false; if (documents == null) { if (other.documents != null) return false; } else if (!documents.equals(other.documents)) return false; if (email == null) { if (other.email != null) return false; } else if (!email.equals(other.email)) return false; if (experiences == null) { if (other.experiences != null) return false; } else if (!experiences.equals(other.experiences)) return false; if (firstName == null) { if (other.firstName != null) return false; } else if (!firstName.equals(other.firstName)) return false; if (id != other.id) return false; if (languages == null) { if (other.languages != null) return false; } else if (!languages.equals(other.languages)) return false; if (lastName == null) { if (other.lastName != null) return false; } else if (!lastName.equals(other.lastName)) return false; if (mobile == null) { if (other.mobile != null) return false; } else if (!mobile.equals(other.mobile)) return false; if (password == null) { if (other.password != null) return false; } else if (!password.equals(other.password)) return false; if (phone == null) { if (other.phone != null) return false; } else if (!phone.equals(other.phone)) return false; if (posts == null) { if (other.posts != null) return false; } else if (!posts.equals(other.posts)) return false; if (stateUser != other.stateUser) return false; if (trainings == null) { if (other.trainings != null) return false; } else if (!trainings.equals(other.trainings)) return false; return true; }
/** Returns true if local_addr is member of mbrs, else false */ protected boolean checkSelfInclusion(Vector mbrs) { Object mbr; if (mbrs == null) return false; for (int i = 0; i < mbrs.size(); i++) { mbr = mbrs.elementAt(i); if (mbr != null && local_addr.equals(mbr)) return true; } return false; }
// @see java.lang.Object#equals(java.lang.Object) @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Owner other = (Owner) obj; if (address == null) { if (other.address != null) return false; } else if (!address.equals(other.address)) return false; return requestId == other.requestId; }
/** * Debugging routine: returns the index (0..top() - 1) of the handle in this block, or -1 if the * handle was not contained in this block. Does not search successor blocks. */ public int indexOfHandle(Address jniHandle) { for (int i = 0; i < top(); i++) { Address addr = getOopHandleAddress(i); if (addr != null) { if (addr.equals(jniHandle)) { return i; } } } return -1; }
public Object down(Event evt) { switch (evt.getType()) { case Event.TMP_VIEW: case Event.VIEW_CHANGE: handleViewChange((View) evt.getArg()); break; case Event.GET_STATE: Address target; StateTransferInfo info = (StateTransferInfo) evt.getArg(); if (info.target == null) { target = determineCoordinator(); } else { target = info.target; if (target.equals(local_addr)) { log.error("%s: cannot fetch state from myself", local_addr); target = null; } } if (target == null) { log.debug("%s: first member (no state)", local_addr); up_prot.up(new Event(Event.GET_STATE_OK, new StateTransferInfo())); } else { Message state_req = new Message(target) .putHeader(this.id, new StateHeader(StateHeader.STATE_REQ)) .setFlag(Message.Flag.DONT_BUNDLE, Message.Flag.OOB, Message.Flag.SKIP_BARRIER); log.debug("%s: asking %s for state", local_addr, target); // suspend sending and handling of message garbage collection gossip messages, // fixes bugs #943480 and #938584). Wake up when state has been received /*if(log.isDebugEnabled()) log.debug("passing down a SUSPEND_STABLE event"); down_prot.down(new Event(Event.SUSPEND_STABLE, new Long(info.timeout)));*/ waiting_for_state_response = true; start = System.currentTimeMillis(); down_prot.down(new Event(Event.MSG, state_req)); } return null; // don't pass down any further ! case Event.CONFIG: Map<String, Object> config = (Map<String, Object>) evt.getArg(); if (config != null && config.containsKey("flush_supported")) { flushProtocolInStack = true; } break; case Event.SET_LOCAL_ADDRESS: local_addr = (Address) evt.getArg(); break; } return down_prot.down(evt); // pass on to the layer below us }
private static boolean addressEquals(Address a1, Address a2) { if (!a1.equals(a2)) { return false; } final String displayName1 = a1.getPersonal(); final String displayName2 = a2.getPersonal(); if (displayName1 == null) { return displayName2 == null; } else { return displayName1.equals(displayName2); } }
@Override public List<Address> selectConnections(Address leader, List<Address> servers) { List<Address> addresses = new ArrayList<>(servers.size()); addresses.add(address); Collections.shuffle(servers); for (Address address : servers) { if (!address.equals(this.address)) { addresses.add(address); } } return addresses; }
public final void testEquals() { Address address1 = new AddressImpl(); Address address2 = new AddressImpl(); assertTrue(address1.equals(address2)); address1.setCity("lyon"); assertFalse(address1.equals(address2)); address1.setCity(null); address1.setCountry("France"); assertFalse(address1.equals(address2)); address1.setCountry(null); address1.setPostalCode("69"); assertFalse(address1.equals(address2)); address1.setPostalCode(null); address1.setStreetName("rue"); assertFalse(address1.equals(address2)); address1.setStreetName(null); address1.setStreetNumber("1"); assertFalse(address1.equals(address2)); }
// refer to Threads::owning_thread_from_monitor_owner public JavaThread owningThreadFromMonitor(Address o) { if (o == null) return null; for (JavaThread thread = first(); thread != null; thread = thread.next()) { if (o.equals(thread.threadObjectAddress())) { return thread; } } for (JavaThread thread = first(); thread != null; thread = thread.next()) { if (thread.isLockOwned(o)) return thread; } return null; }
// ------------------------------------------------------------ public void removeModule(Address addr) { Enumeration e = virtual.keys(); Address key = addr; while (e.hasMoreElements()) { Address k = (Address) e.nextElement(); if (k.equals(addr)) { virtual.remove(key); layer.shutdown(addr); layer.removeInterface(addr); return; } } }
public void sendDiscoveryRequest(String cluster_name, Promise promise, ViewId view_id) throws Exception { PingData data = null; PhysicalAddress physical_addr = (PhysicalAddress) down(new Event(Event.GET_PHYSICAL_ADDRESS, local_addr)); if (view_id == null) { List<PhysicalAddress> physical_addrs = Arrays.asList(physical_addr); data = new PingData(local_addr, null, false, UUID.get(local_addr), physical_addrs); } PingHeader hdr = new PingHeader(PingHeader.GET_MBRS_REQ, data, cluster_name); hdr.view_id = view_id; Collection<PhysicalAddress> cluster_members = fetchClusterMembers(cluster_name); if (cluster_members == null) { Message msg = new Message(null); // multicast msg msg.setFlag(Message.OOB); msg.putHeader(getId(), hdr); sendMcastDiscoveryRequest(msg); } else { if (cluster_members.isEmpty()) { // if we don't find any members, return immediately if (promise != null) promise.setResult(null); } else { for (final Address addr : cluster_members) { if (addr.equals(physical_addr)) // no need to send the request to myself continue; final Message msg = new Message(addr, null, null); msg.setFlag(Message.OOB); msg.putHeader(this.id, hdr); if (log.isTraceEnabled()) log.trace("[FIND_INITIAL_MBRS] sending discovery request to " + msg.getDest()); if (!sendDiscoveryRequestsInParallel()) { down_prot.down(new Event(Event.MSG, msg)); } else { timer.execute( new Runnable() { public void run() { try { down_prot.down(new Event(Event.MSG, msg)); } catch (Exception ex) { if (log.isErrorEnabled()) log.error("failed sending discovery request to " + addr + ": " + ex); } } }); } } } } }
// --------------------------------------------------------------- public void entityShutdown(Address addr) { Enumeration e = external.elements(); while (e.hasMoreElements()) { Address a = (Address) e.nextElement(); if (a.equals(addr)) { external.remove(a); // Inform listeners Enumeration ee = virtual.elements(); while (ee.hasMoreElements()) ((VirtualMBusListener) ee.nextElement()).entityShutdown(addr); return; } } }
// ------------------------------------------------------------ public void addModule(VirtualMBusListener mod, Address addr) { Enumeration e = virtual.keys(); Address key = addr; while (e.hasMoreElements()) { Address k = (Address) e.nextElement(); if (k.equals(addr)) { key = k; break; } } // Add module to listeners virtual.put(key, mod); layer.addInterface(addr); }
private synchronized void handleViewChange(View view, boolean makeServer) { if (makeServer) initializeNewSymmetricKey(view instanceof MergeView); // if view is a bit broken set me as keyserver List<Address> members = view.getMembers(); if (members == null || members.isEmpty() || members.get(0) == null) { becomeKeyServer(local_addr, false); return; } // otherwise get keyserver from view controller Address tmpKeyServer = view.getMembers().get(0); // I am keyserver - either first member of group or old key server is no more and // I have been voted new controller if (makeServer || (tmpKeyServer.equals(local_addr))) becomeKeyServer(tmpKeyServer, makeServer); else handleNewKeyServer(tmpKeyServer, view instanceof MergeView); }
@ManagedOperation(description = "Reads data from local caches and dumps them to a file") public void dumpCache(String output_filename) throws Exception { Map<Address, PhysicalAddress> cache_contents = (Map<Address, PhysicalAddress>) down_prot.down(new Event(Event.GET_LOGICAL_PHYSICAL_MAPPINGS, false)); List<PingData> list = new ArrayList<>(cache_contents.size()); for (Map.Entry<Address, PhysicalAddress> entry : cache_contents.entrySet()) { Address addr = entry.getKey(); PhysicalAddress phys_addr = entry.getValue(); PingData data = new PingData(addr, true, UUID.get(addr), phys_addr).coord(addr.equals(local_addr)); list.add(data); } OutputStream out = new FileOutputStream(output_filename); write(list, out); }
protected void handleConsumerFoundResponse(long threadId, Address address) { final Runnable runnable = _awaitingConsumer.poll(); // This is a representation of the server side owner running our task. Owner owner; if (runnable == null) { owner = new Owner(address, threadId); // For some reason we don't have a runnable anymore // so we have to send back to the coordinator that // the consumer is still available. The runnable // would be removed on a cancel sendToCoordinator(Type.CONSUMER_READY, owner.getRequestId(), owner.getAddress()); } else { final Long requestId = _requestId.get(runnable); if (requestId == null) { // requestId is not available - this means the result has been // returned already or it has been interrupted return; } owner = new Owner(address, requestId); _awaitingReturn.put(owner, runnable); // If local we pass along without serializing if (local_addr.equals(owner.getAddress())) { handleTaskSubmittedRequest(runnable, local_addr, requestId, threadId); } else { try { if (runnable instanceof DistributedFuture) { Callable<?> callable = ((DistributedFuture<?>) runnable).getCallable(); sendThreadRequest( owner.getAddress(), threadId, Type.RUN_SUBMITTED, requestId, callable); } else { sendThreadRequest( owner.getAddress(), threadId, Type.RUN_SUBMITTED, requestId, runnable); } } // This relies on the Mesasge class to throw this when a // serialization issue occurs catch (IllegalArgumentException e) { ExecutorNotification notificiation = notifiers.remove(runnable); if (notificiation != null) { notificiation.throwableEncountered(e); } throw e; } } } }
protected void getState(Address target, long timeout, Callable<Boolean> flushInvoker) throws Exception { checkClosedOrNotConnected(); if (!state_transfer_supported) throw new IllegalStateException( "fetching state will fail as state transfer is not supported. " + "Add one of the state transfer protocols to your configuration"); if (target == null) target = determineCoordinator(); if (target != null && local_addr != null && target.equals(local_addr)) { log.trace( local_addr + ": cannot get state from myself (" + target + "): probably the first member"); return; } boolean initiateFlush = flushSupported() && flushInvoker != null; if (initiateFlush) { boolean successfulFlush = false; try { successfulFlush = flushInvoker.call(); } catch (Throwable e) { successfulFlush = false; // http://jira.jboss.com/jira/browse/JGRP-759 } if (!successfulFlush) throw new IllegalStateException( "Node " + local_addr + " could not flush the cluster for state retrieval"); } state_promise.reset(); StateTransferInfo state_info = new StateTransferInfo(target, timeout); long start = System.currentTimeMillis(); down(new Event(Event.GET_STATE, state_info)); StateTransferResult result = state_promise.getResult(state_info.timeout); if (initiateFlush) stopFlush(); if (result == null) throw new StateTransferException( "timeout during state transfer (" + (System.currentTimeMillis() - start) + "ms)"); if (result.hasException()) throw new StateTransferException("state transfer failed", result.getException()); }
@Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; if (checked != person.checked) return false; if (id != person.id) return false; if (version != person.version) return false; if (address != null ? !address.equals(person.address) : person.address != null) return false; if (birthDate != null ? !birthDate.equals(person.birthDate) : person.birthDate != null) return false; if (family != null ? !family.equals(person.family) : person.family != null) return false; if (firstName != null ? !firstName.equals(person.firstName) : person.firstName != null) return false; return true; }
@Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Account other = (Account) obj; if (alamat == null) { if (other.alamat != null) return false; } else if (!alamat.equals(other.alamat)) return false; if (id != other.id) return false; if (kontak == null) { if (other.kontak != null) return false; } else if (!kontak.equals(other.kontak)) return false; if (nama == null) { if (other.nama != null) return false; } else if (!nama.equals(other.nama)) return false; if (tanggalBuat == null) { if (other.tanggalBuat != null) return false; } else if (!tanggalBuat.equals(other.tanggalBuat)) return false; return true; }